【面向對象設計原則】之里氏替換原則(LSP)

  里氏代換原則由2008年圖靈獎得主、美國第一位計算機科學女博士Barbara Liskov教授和卡內基·梅隆大學Jeannette Wing 教授於1994年提出,因此使用的是這位女博士的性命名的一個設計原則。html

里氏替換原則(Liskov Substitution Principle, LSP):全部引用父類的地方必須能使用其子類的對象。ide

從這個概念能夠看出這個原則是面向對象多態的一種具體實踐。通俗來說 「老爸能幹的事情,兒子都能幹」, 由於兒子繼承了老爸的基因。 反過來說就不對了,時代在變化,新一代雖然繼承了老一代的優良傳統,可是在時代的影響下,新一代有了一些新的特性,老一代可能就不具有了,好比如今的年輕人會打遊戲,可是他爸不必定會。老爸會騎自行車,換成兒子也能騎。spa

一樣的里氏代換原則告訴咱們,在軟件中將一個基類對象替換成它的子類對象,程序將不會產生任何錯誤和異常,反過來則不成立,若是一個軟件實體使用的是一個子類對象的話,那麼它不必定可以使用父類對象。設計

咱們定義一個父類叫Animal, 其包含一個方法叫Say以下:code

    public class Animal
    {
        private readonly string _sayContent;

        public Animal(string sayContent)
        {
            _sayContent = sayContent;
        }
        public virtual void Say()
        {
            Console.WriteLine($"Animal Say:{_sayContent}");
        }
    }

再定義一個子類Pig 集成自Animal,並覆蓋父類中的Say 方法以下:htm

    public class Pig:Animal
    {
        private readonly string _sayContent;

        public Pig(string sayContent) : base(sayContent)
        {
            _sayContent = sayContent;
        }

        public override void Say()
        {
            Console.WriteLine($"Pig Say:{_sayContent}");
        }
    }

如今咱們在調用方建立一個Animal的對象並調用Say方法:對象

            Animal animal = new Animal("This is a parent class.");
            animal.Say();

輸出結果:blog

Animal Say:This is a parent class.繼承

下來咱們建立一個Pig對象賦給animal 對象並調用Say方法:接口

        static void Main(string[] args)
        {
            Animal animal = new Animal("This is a parent class.");
            animal.Say();

            animal = new Pig("This is a sub class.");
            animal.Say();

            Console.ReadKey();
        }

輸出:

image

能夠看出將子類的對象賦給父類的對象,而且獲得了咱們指望的結果。

里氏替換原則是實現開閉原則的重要方式之一(其實其它原則都是實現開閉原則OCP重要方式之一,上一篇【面向對象設計原則】之開閉原則(OCP) 有說起),因爲使用父類對象的地方均可以使用子類對象,所以在程序中儘可能使用父類類型來對對象進行定義,而在運行時再肯定其子類類型,用子類對象來替換父類對象。一般咱們會使用接口或者抽象方法定義基類,而後子類中實現父類的方法,並在運行時經過各類手段進行類型選擇調用(好比反射)。

在使用里氏替換原則時須要注意以下幾個問題:

      (1)子類的全部方法必須在父類中聲明,或子類必須實現父類中聲明的全部方法。根據里氏替換原則,爲了保證系統的擴展性,在程序中一般使用父類來進行定義,若是一個方法只存在子類中,在父類中不提供相應的聲明,則沒法在以父類定義的對象中使用該方法。

      (2)  咱們在運用里氏替換原則時,儘可能把父類設計爲抽象類或者接口,讓子類繼承父類或實現父接口,並實如今父類中聲明的方法,運行時,子類實例替換父類實例,咱們能夠很方便地擴展系統的功能,同時無須修改原有子類的代碼,增長新的功能能夠經過增長一個新的子類來實現。里氏替換原則是開閉原則的具體實現手段之一。這也就是咱們應該更多的依賴抽象,儘可能少的依賴實現細節, 其實就是咱們下一篇要講的依賴倒置原則(DIP)。

相關文章
相關標籤/搜索