多態是什么?
用一句話來概括下,多態就是同一操作(方法)作用於不同的對象時,可以有不同的解釋,產生不同的執行結果。這句話看似簡
單,實則頗有深意。下面我們來深入理解一多態的意義及如何使用多態。
使用多態編程的好處
在使用繼承編程的時候,我們一般是把不同子類的方法分別寫在不同的子類中,使用的時候用is a關鍵字來判斷對象是哪種類型
的,然后進行強制轉換來使用不同對象的方法。
但是,如果有多個子類的話,使用的時候難道要寫多個if語句來判斷對象是哪種類型的嗎?這樣會產生很多冗余代碼,也會很繁
瑣。
使用多態編程可以很好的解決這個問題。在父類寫一個虛方法或抽象方法,子類去重寫父類的方法,在調用的時候系統會根據對
象運行時的類型決定調用哪個方法。這樣子是不是簡潔多了?
小例子
假設我們有一個“書”類,然后有很多子類繼承“書”類。例如“計算機組成原理”類繼承“書類”,“深入Java面向對象”繼承“書”類...
而這些子類都有類似的方法,即被不同的人使用。
下面我們來用代碼實現它。
1 /// <summary> 2 /// 演示類 3 /// </summary> 4 class Demo 5 { 6 List<Book> books = new List<Book>(); 7 8 /// <summary> 9 /// 測試 10 /// </summary> 11 public void Test() 12 { 13 books.Add(new ComputerBook()); 14 books.Add(new JavaBook()); 15 16 foreach (Book item in books) 17 { 18 if (item is ComputerBook) 19 { 20 ((ComputerBook)item).ByReading(); 21 } 22 if (item is JavaBook) 23 { 24 ((JavaBook)item).ByReading(); 25 } 26 } 27 } 28 } 29 30 /// <summary> 31 /// 書類 32 /// </summary> 33 class Book 34 { 35 36 } 37 38 /// <summary> 39 /// 計算機書籍 40 /// </summary> 41 class ComputerBook : Book 42 { 43 /// <summary> 44 /// 被閱讀 45 /// </summary> 46 public void ByReading() 47 { 48 Console.WriteLine("我是計算機類書籍,被在校大學生使用。"); 49 } 50 } 51 52 /// <summary> 53 /// Java書籍 54 /// </summary> 55 class JavaBook : Book 56 { 57 /// <summary> 58 /// 被閱讀 59 /// </summary> 60 public void ByReading() 61 { 62 Console.WriteLine("我是Java書籍,被在業Java程序員使用。"); 63 } 64 }
通過這段代碼可以發現:在使用子類對象的時候需要先用is a來判斷子類對象時哪種類型的。那么也就是說,如果一個父類有10
個派生類(子類)的話,就要用10個if判斷語句來判斷子類對象是哪種類型了,未免太過繁瑣。
這時,虛方法就該登場了。
虛方法
概念:
虛方法有方法體,可以被重寫,使用virtual來修飾。
父類中的虛方法並非必須被子類重寫,在父類中可以給出虛方法的默認實現。如果子類不重寫父類的虛方法則依然執行
父類的默認實現。如果子類重寫了父類的虛方法,則執行子類重寫后的方法。
其實方法重載也是實現多態的一種形式,只是重載的方法都在同一個類中,而用虛方法實現多態的方法散布在有繼承關
系的多個類中。
使用:
在父類中使用virtual關鍵字定義虛方法,在子類中使用override關鍵字來重寫父類中的虛方法。
override關鍵字:
通過override關鍵字來修飾的方法,稱為方法的重寫。
下面我們用虛方法來改造一下上面的例子
1 /// <summary> 2 /// 演示類 3 /// </summary> 4 class Demo 5 { 6 List<Book> books = new List<Book>(); 7 8 /// <summary> 9 /// 測試 10 /// </summary> 11 public void Test() 12 { 13 books.Add(new ComputerBook()); 14 books.Add(new JavaBook()); 15 //遍歷時不用加判斷 16 foreach (Book item in books) 17 { 18 item.ByReading(); 19 } 20 } 21 } 22 23 /// <summary> 24 /// 書類 25 /// </summary> 26 class Book 27 { 28 public virtual void ByReading() 29 { 30 31 } 32 } 33 34 /// <summary> 35 /// 計算機書籍 36 /// </summary> 37 class ComputerBook : Book 38 { 39 /// <summary> 40 /// 被閱讀 41 /// </summary> 42 public override void ByReading() 43 { 44 Console.WriteLine("我是計算機類書籍,被在校大學生使用。"); 45 } 46 } 47 48 /// <summary> 49 /// Java書籍 50 /// </summary> 51 class JavaBook : Book 52 { 53 /// <summary> 54 /// 被閱讀 55 /// </summary> 56 public override void ByReading() 57 { 58 Console.WriteLine("我是Java書籍,被在業Java程序員使用。"); 59 } 60 }
可以看出,使用虛方法來寫代碼簡便了許多。但是問題又來了,一般子類的父類和在父類中的虛方法是“宏觀”的,“抽象”的,我
們不想讓這個父類被實例化並且只提供方法的定義,由子類去實現這個方法,該怎么做呢?
如何解決這個問題呢?我們可以使用抽象類和抽象方法來實現。
抽象類和抽象方法
abstract關鍵字:
abstract關鍵字用來修飾抽象類和抽象方法。
抽象類:
使用abstract關鍵字修飾的抽象類不能被實例化。
抽象類中可以有非抽象方法。
抽象類不能是密封的或者靜態的。
抽象方法:
使用abstract關鍵字修飾的抽象方法是一個沒有實現的方法,由子類重寫抽象方法來實現。
抽象方法沒有大括號,直接在小括號后以分號";"結尾。
含有抽象方法的類必須是抽象類。
抽象方法必須在其子類中實現,除非它的子類也是抽象類。
下面我們使用抽象類和抽象方法再次改造上面的例子
1 /// <summary> 2 /// 演示類 3 /// </summary> 4 class Demo 5 { 6 List<Book> books = new List<Book>(); 7 8 /// <summary> 9 /// 測試 10 /// </summary> 11 public void Test() 12 { 13 books.Add(new ComputerBook()); 14 books.Add(new JavaBook()); 15 //遍歷時不用加判斷 16 foreach (Book item in books) 17 { 18 item.ByReading(); 19 } 20 } 21 } 22 23 /// <summary> 24 /// 書類 25 /// </summary> 26 abstract class Book 27 { 28 public abstract void ByReading(); 29 } 30 31 /// <summary> 32 /// 計算機書籍 33 /// </summary> 34 class ComputerBook : Book 35 { 36 /// <summary> 37 /// 被閱讀 38 /// </summary> 39 public override void ByReading() 40 { 41 Console.WriteLine("我是計算機類書籍,被在校大學生使用。"); 42 } 43 } 44 45 /// <summary> 46 /// Java書籍 47 /// </summary> 48 class JavaBook : Book 49 { 50 /// <summary> 51 /// 被閱讀 52 /// </summary> 53 public override void ByReading() 54 { 55 Console.WriteLine("我是Java書籍,被在業Java程序員使用。"); 56 } 57 }
到了這里,我們可以發現使用虛方法和抽象方法來編程(也就是多態)更符合面向對象編程的思想,並且可以大幅的提升代碼的
可讀性和減少冗余的代碼。
用更少的代碼實現相同的實現,這感覺,很爽的。