面向對象三大特性:封裝,繼承,多態
封裝: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("我是一隻企鵝,我喜歡吃魚");
}
}
}