面向對象程式設計領域有個非常重要的概念,那就是多态,但是你真的了解這到底是什麼意思嗎?程式員該如何了解多态?
英文中的多态
多态一詞其英文為“polymorphism”,在講解多态之前讓我們來分析一下這個單詞。
這個單詞其實包含了兩部分,一部分是poly;另一部分是morph,這兩個詞在希臘語中是很多詞的詞根:
- poly,在希臘語中原指許多的意思,包含poly這個詞根的有:polygon,即多邊形;polygolt,即多語言。
- morph,原指形态,包含morph這個詞根的有:morphology,即形态學;morpheus,即希臘神話中的夢神,可以幻化成任何形态,值得一提的是,電影《黑客帝國》找到Neo的男主角之一就叫morpheus,中文譯作了墨菲斯。
現在這兩個單詞拼湊在一起的polymorphism意思就直白多了,在程式設計語言當中,多态是指用相同的接口去表示不同的實作。
加一點代碼:為什麼使用多态
讓我們用一點代碼來說明問題,假設代碼中有三個class: 自行車(Bicycle)、汽車(Car)和卡車(Truck),這三個class分别有這樣三個實作:Ride()、Run()、Launch(),實際上都是讓它們發動起來,如果沒有多态的話我們該怎樣開動它們呢?(注意這裡沒有采用特定語言,因為多态是一個通用的概念)
// 實作部分 Bicycle bicyle = new Bicycle(); Car car = new Car(); Truck truck = new Truck(); // 使用部分 bicyle.Ride(); car.Run(); truck.Launch();
注意,以上代碼包含了兩部分:一部分是類的實作;另一部分是類的使用,意識到這一點對于了解多态非常關鍵。
現在我們已經知道了使用類的代碼包含兩部分,在這樣的代碼實作中如果Bicyle的接口修改了,那麼使用部分的代碼同樣需要修改,這是程式員所不想看到的。如果有多态會怎樣呢?
實際上自行車(Bicycle)、汽車(Car)和卡車(Truck)都是交通工具(Vehicle),把它們發動起來都是讓它們Run起來,是以,如果有多态的話我們可以這樣寫代碼:
// 實作部分 List<Vehicle> vehicles = { new Bicycle(), new Car(), new Truck() }; // 使用部分 for (v : vechicles) v.Run();
怎麼樣,代碼是不是一下就簡潔多了,最棒的是不管實作部分代碼怎麼改動都不會影響到使用部分的代碼,實際上你可以往vehicles中增加任意多對象都不會影響到使用部分,這就是設計模式當中所謂的"隻針對抽象程式設計,而不是針對實作程式設計"。
是以我們可以看到,盡管自行車、汽車、卡車是不同的東西,但是當我們将其抽象為交通工具後就可以一視同仁的對待它們,這就是多态。
現在你應該了解什麼是多态以及為什麼需要多态了吧。
當然為了實作多态,類的定義要稍稍改動一下:
class Vehicle { // 新增抽象類 void Run() {} } class Bicycle: Vehicle { void Run() {......} // Ride修改為Run } class Car: Vehicle{ voie Run() {......} // 無需改動 } class Truck: Vehicle { void Run() {......} // Launch修改為Run }
實際上如果你仔細想想的話整數和浮點數就是一種多态,因為你可以把一個整數和一個浮點數相加,也就是以相同的方式使用它們,盡管整數和浮點數是兩個不同的資料類型。
有趣的類比
接下來使用一個類比來加深大家對多态的了解。
假如美國總統想使用多态的話他該怎麼用呢?
首先,美國總統有許多幕僚:五角大樓部長(Military Advisers)、司法部部長(Legal Advisers)、能源部部長(Energy)、醫療健康部長(Medical Advisers)等等。
在程式設計領域中實作與使用應該盡可能隔離,就像你不能指望總統精通每一件事一樣,美國總統不是這些領域的專家,總統不熟悉的東西很多,但他知道一件事:如何運轉一個國家,如果沒有多态的話總統該怎樣運轉一個國家呢?
class President { void RunCountry() { // 總統根據每個人的身份來告訴它們具體該做些什麼 // 五角大樓部長Tom tom.IncreaseTroopNumbers(); tom.ImproveSecurity(); // 能源部部長Jerry jerry.FindOil(); jerry.buildMoreOilShip(); // 醫療健康部長John John.IncreasePremiums(); John.AddPreexistingConditions(); } }
在這裡我們可以看到,總統正在事實親力親為:總統即需要了解增加軍隊數量又需要知道去哪裡開采更多石油,這就意味着如果中東政策改變後總統必須修改其下發的指令,同樣五角大樓部長Tom類也要修改。實際上我們想要的是隻改變五角大樓部長Tom類而不應該修改總統類,因為總統是很忙的,總統不應該關心這些具體細節,總統想要的隻是發出指令,剩下的就交給這些部長了,這樣總統就有更多的時間去打高爾夫啦 :)
為了讓總統有時間去打高爾夫,使用多态是一個很好的辦法。
多态本質上就是讓我們實作一個抽象類或者更具體的就是給出一組通用的接口(common interface),也就是讓各個部長Tom、Jerry、John實作一個接口,姑且就叫“Advise()”,這樣總統的任務就簡單多了:
class President { void RunCountry(Ministers ministers) { for (m : ministers) m.Advise(); } }
是以我們可以看到總統實際上不需要關心細節,所有細節都交給各個部長;總統需要做的就是找到各個部長然後聽取它們的意見即可。
總結
在這裡我們詳細講解了面向對象程式設計領域中一個非常重要的概念,多态。
多态可以讓程式員針對抽象而不是具體實作來程式設計,這樣的代碼會有更好的可擴充性。
當然為了使用多态你需要進行抽象,也就是定義一個接口讓不同的對象去實作,這樣從這個接口的角度看各個對象就一樣了,是以可以以一緻的方式來使用這些不同類型的對象,這就是多态的威力。
今天就到這了,希望這篇文章能幫到你。
更多精彩内容,歡迎關注公衆号“碼農的荒島求生”。