C# 多態(一)

面向對象三大特性:封裝,繼承,多態


封裝:1、在程序上,隱藏對象的屬性和實現細節,僅對外公開接口,控制在程序中屬性的讀和修改的訪問級別;將抽象得到的數據和行爲(或功能)相結合,形成一個有機的整體,也就是將數據與操作數據的源代碼進行有機的結合,形成“類”,其中數據和函數都是類的成員。


繼承:指一個對象直接使用另一對象的屬性和方法。


多態:是允許你將父對象設置成爲和一個或更多的他的子對象相等的技術,賦值之後,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許將子類類型的指針賦值給父類類型的指針。


上述三個均爲比較官方的解釋。


而這裏只講多態

多態:允許將子類類型的指針賦值給父類類型的指針。即:同一操作作用於不同的對象,可以有不同的解釋。

    允許時,可以通過指向基類的指針,來調用實現派生類中的方法。

里氏替換原則:派生類(子類)對象能夠替換其基類(超類)對象被使用。通俗來講:子類即父類。

                            eg:男人是人,人不一定是男人。當需要一個父類類型的對象的時候可以給一個子類類型的對象;當需要一個子類類型對象的時候是不能給一個父類類型對象的!

開放封閉原則:封裝變化,降低耦合。軟件實體應該是可擴展,而不可修改。即:對擴展是開放的,對修改是封閉的。

                            因此開放封閉原則體現在:

      1.對擴展開放,意味着有新的需求或變化時,可以對現有代碼進行擴展,以適應新的情況。

                          2.對修改封閉,意味着類一旦設計完成,就可以獨立完成其工作,而不要對類進行任何修改。


而多態的設計剛好符合上述兩個原則


以鳥爲例

我們知道,喜鵲(Magpie)、老鷹(Eagle)、企鵝(Penguin)均屬於鳥類,根據三者共有特性提取出鳥類(Bird)爲父類。

喜鵲喜歡吃蟲子,老鷹喜歡吃肉,企鵝喜歡吃魚。


先寫一個父類Bird,創建Eat虛方法



再創建喜鵲,老鷹,企鵝三個子類,並重寫Eat方法



至此,三個子類創建完畢,下面我們再看看主函數中多態是怎樣體現的



運行:



由此可見,子類Magpie,Eagle,Penguin對象賦值給父類對象,即父類類型指針可以指向子類類型對象,這裏體現了里氏替換原則。

父類對象調用自己的Eat()方法,實際上顯示的是父類類型指針指向的子類類型對象重寫父類Eat後的方法。這就是多態。

多態的作用到底是什麼呢?
其實多態的作用就是把不同的子類對象都當作父類來看,可以屏蔽不同子類對象之間的差異,寫出通用的代碼,做出通用的編程,以適應需求的不斷變化。
以上程序也體現了開放封閉原則,如果以後有人需要擴展這個程序,還想再添加一個貓頭鷹(Owl),很容易,只需要添加一個Owl類,繼承Bird,重寫Eat()方法,添加給父類對象就可以了。至此,該程序的擴展性得到了提升,而又不需要查看源代碼是如何實現的就可以擴展新功能。這就是多態帶來的好處。


附代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Polymorphism
{
    class Program
    {
        static void Main(string[] args)
        {
            Bird[] birds ={
                             new Bird(),
                             new Magpie(),
                             new Eagle(),
                             new Penguin()
                         };
            foreach(Bird bird in birds)
            {
                bird.Eat();
            }
            Console.ReadKey();
        }
    }

    /// <summary>
    /// 鳥類(父類)
    /// </summary>
    public class Bird
    {
        /// <summary>
        /// 吃(虛方法)
        /// </summary>
        public virtual void Eat()
        {
            Console.WriteLine("我是一隻鳥,我喜歡吃蟲子");
        }
    }

    /// <summary>
    /// 喜鵲類(繼承:鳥類)
    /// </summary>
    public class Magpie:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻喜鵲,我喜歡吃蟲子");
        }
    }

    /// <summary>
    /// 老鷹類(繼承:鳥類)
    /// </summary>
    public class Eagle:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻老鷹,我喜歡吃肉");
        }
    }

    /// <summary>
    /// 企鵝類(繼承:鳥類)
    /// </summary>
    public class Penguin:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻企鵝,我喜歡吃魚");
        }
    }

}


下面我們再來看看利用抽象如何來實現多態。


剛纔的例子中,我們發現Bird這個父類,我們根本不需要使用它創建的對象,它存在的意義就是供子類來繼承。所以我們可以用抽象類來優化它。
我們把Bird父類改成抽象類,Eat()方法改成抽象方法。



抽象類Bird內添加一個Eat()抽象方法,沒有方法體。也不能實例化。
其他類Magpie,Eagle,Penguin代碼不變,子類還是用override關鍵字來重寫父類中抽象方法。

這樣,Bird類也就不能實例化了。


運行:



由此可見,我們選擇使用虛方法實現多態還是抽象類抽象方法實現多態,取決於我們是否需要使用基類實例化的對象。


附代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Polymorphism
{
    class Program
    {
        static void Main(string[] args)
        {
            Bird[] birds ={
                             new Magpie(),
                             new Eagle(),
                             new Penguin()
                         };
            foreach(Bird bird in birds)
            {
                bird.Eat();
            }
            Console.ReadKey();
        }
    }

    /// <summary>
    /// 鳥類(父類<抽象類>)
    /// </summary>
    public abstract class Bird
    {
        /// <summary>
        /// 吃(抽象方法)
        /// </summary>
        public abstract void Eat();
    }

    /// <summary>
    /// 喜鵲類(繼承:鳥類)
    /// </summary>
    public class Magpie:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻喜鵲,我喜歡吃蟲子");
        }
    }

    /// <summary>
    /// 老鷹類(繼承:鳥類)
    /// </summary>
    public class Eagle:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻老鷹,我喜歡吃肉");
        }
    }

    /// <summary>
    /// 企鵝類(繼承:鳥類)
    /// </summary>
    public class Penguin:Bird
    {
        /// <summary>
        /// 吃(重寫父類吃方法)
        /// </summary>
        public override void Eat()
        {
            Console.WriteLine("我是一隻企鵝,我喜歡吃魚");
        }
    }

}


發佈了45 篇原創文章 · 獲贊 53 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章