1. 程式人生 > >C#菜鳥之旅-----里氏替換

C#菜鳥之旅-----里氏替換

     這是第二次學習“里氏替換”,因為經過了小組的討論和自己今天的研究,感覺對於這個理解更深刻了,於是在學習完之後立刻整理,希望大家可以從這篇部落格中有新的收穫。

      對於百度上“大話設計模式”書中對於“里氏替換”的概念都是:    

       “派生類(子類)物件能夠替換其基類(父類)物件使用”   ,而且他們的功能並不會發生變化。  

        但是為什麼子類就可以替換父類,而且整個程式的功能不會受到影響呢? 

        原因:   當我們寫的關係滿足繼承的時候,父類中會存在非私有(非private)成員,這個時候,子類肯定是得到了父類的這些非私有成員(假設,父類的成員全部都是私有的,那麼子類沒辦法從父類繼承任何成員,(這裡有的網友也說是被繼承了,只不過是無法訪問)),既然子類繼承了父類的非私有成員,那麼父類物件也就可以在子類物件中呼叫這些非私有成員。

        我們先來根據小楊老師看看他講的“里氏替換”的四種轉換的型別:

 

定義了一個父類 Person,倆個子類:分別是student  ,teacher  , 
Int num=10;
Double dou=num;


第一種:
Person P =new Teacher();

Teacher t =(Teacher) p   ;  //這是是強制轉換
//如果 new的是子類 ,那麼父類可以轉換為子類  這樣的是可以的

第二種:
Person p =new Person();
Student stu=(Student) p ;
  //如果new的是父類,那麼在轉換子類的時候是不可以的

第三種:

Person p =new Teacher()
Student stu=(student)p;
//結果報異常,new的雖然是子類,但是轉的卻是另外一個子類;
//即new 的子類 和 轉換的子類不是同一個類。

第四種:
子類轉換成父類的時候就不需要強制轉換,隱氏轉換就可以了
Student stu=new student()
Person p =stu;
p.Show();
Console.readkey();
 
不會出現錯誤

通過上面小楊老師的講解我們能夠很清晰的清楚,在什麼情況下我們才可以將父類替換成子類---或者說是用子類來替換父類。

下面我們再來通過一個例子來研究一下“里氏替換”:

class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();

            Person p1 = new Student();

            Console.ReadKey();
        }
    }

    class Person
    {
    //父類的私有成員
    private int nAge;


        public Person()
        {
            Console.WriteLine("我是Person建構函式,我是一個人!");
        }

        public void Say()
        {
            Console.WriteLine("我是一個人!");
        }

    }

    class Student : Person
    {
        public Student()
        {
            Console.WriteLine("我是Student建構函式,我是一個學生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一個學生!");
        }
    }

    class SeniorStudent : Student
    {
        public SeniorStudent()
        {
            Console.WriteLine("我是SeniorStudent建構函式,我是一個高中生!");
        }
        public  void SaySenior()
        {
            Console.WriteLine("我是一個高中生!");
        }
    }

執行後的結果是:

然後我們在Main()函式中新增一些程式碼其他的地方不改變:

static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();
  
            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }

繼續執行,結果是:

而且在我輸入程式碼的過程中,一個細節我發現,當我輸入p.的時候,它後面的方法只有say,說明父類只可以訪問父類的方法

在經過了 

person p1=new student(); 之後 輸入p1.的時候後面也只顯示 say 方法。

 所以這裡就滿足了里氏替換原則,子類的student 物件替換了父類person 物件的位置

二,虛方法中的里氏替換。

虛方法: 使用virtual關鍵字修飾的方法,叫作虛方法(一般都是在父類當中)

下面看一段關於虛方法的程式碼:

namespace ConsoleApp45
{
    class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.Say();

            Person p1 = new Student();
            p1.Say();

            Student s = new Student();
            s.Say();
            Console.ReadKey();
        }
    }
    class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person建構函式,我是一個人!");
        }

        //這裡定義了一個虛方法
        public virtual void Say()
        {
            Console.WriteLine("我是一個人!");
        }

    }

    class Student : Person
    {
        //子類使用override關鍵字改寫了父類的虛方法
        public override void Say()
        {
            Console.WriteLine("我是一個學生!");
        }
        public Student()
        {
            Console.WriteLine("我是Student建構函式,我是一個學生!");
        }

        public void SayStude()
        {
            Console.WriteLine("我是一個學生!");
        }
    }
}

最終結果顯示:

從上面的結果中可以看出,第二個表示式滿足里氏替換原則,p1.say()執行的本該是父類的方法,但是卻執行了子類的say方法

這就是子類使用override關鍵字覆蓋了父類的虛方法

 上面的這種情況是在父類的方法中寫了“virtual” 同時子類中的方法也寫了 override 

那麼如果父類中用 virtual修飾之後,而子類沒有重寫該方法。結果會是怎麼樣呢?


namespace ConsoleApp45
{

    class Program
    {
        static void Main(string[] args)
        {

            Person p1 = new Student();
            p1.Say();
            Console.ReadKey();
        }
    }

    class Person
    {
        private int nAge;
        public Person()
        {
            Console.WriteLine("我是Person建構函式,我是一個人!");
        }

        //這裡定義了一個虛方法
        public virtual void Say()
        {
            Console.WriteLine("我是一個人!");
        }

    }

    class Student : Person
    {
        //子類中沒有出現override關鍵字修飾的方法


        public void SayStude()
        {
            Console.WriteLine("我是一個學生!");
        }
    }
}

結果顯示:

所以,如果子類中找不到 override 方法,就會回到子類的父類去找是否有 virtual並執行