多態(tài)

多態(tài)的含義

多態(tài)的實(shí)際含義是:同一操作作用于不同的對(duì)象什么全景,可以產(chǎn)生不同的解釋和不同的執(zhí)行結(jié)果耀石。換句話說(shuō),給不同的對(duì)象發(fā)送同一個(gè)消息的時(shí)候爸黄,這些對(duì)象會(huì)根據(jù)這個(gè)消息分別給出不同的反饋滞伟。

舉例說(shuō)明:

主人家里養(yǎng)了一只雞和一只鴨,當(dāng)主人向它們發(fā)出“叫”的指令時(shí)炕贵,鴨會(huì)“嘎嘎嘎”地叫梆奈,而雞會(huì)“咯咯咯”地叫。根據(jù)主人的指令称开,這兩只動(dòng)物都以各自的形式來(lái)響應(yīng)亩钟。

let makeSound = function(animal) {
  if (animal instanceof Duck) {
    console.log("嘎嘎嘎");
  } else if (animal instanceof Chicken) {
    console.log("咯咯咯");
  }
}

let Duck = function() {};
let Chicken = function() {};

makeSound(new Duck());        // 嘎嘎嘎
makeSound(new Chicken());      // 咯咯咯

這段代碼體現(xiàn)了“多態(tài)”乓梨,但是這樣的“多態(tài)”并不能讓人滿意。如果后來(lái)又增加一條狗清酥,就必須得改動(dòng) makeSound 函數(shù)扶镀,才能讓狗發(fā)出叫聲。

多態(tài)背后的思想是將“做什么”和“誰(shuí)去做以及怎么做”分離開來(lái)焰轻,也就是將“不變的事物”與“可能改變的事物”分離開臭觉。在這里,動(dòng)物都會(huì)叫辱志,這是不變的蝠筑,但是不同類型的動(dòng)物具體怎么叫是可變的。把不變的部分隔離揩懒,把可變的部分封裝什乙,就可以賦予程序擴(kuò)展的能力,也是符合開放-封閉原則的已球,相對(duì)與修改代碼來(lái)說(shuō)稳强,僅增加代碼就能完成同樣的功能,這顯然優(yōu)雅和安全得多和悦。

對(duì)象的多態(tài)性

從靜態(tài)類型語(yǔ)言(如 Java)與動(dòng)態(tài)類型語(yǔ)言(如 Javascript)兩方面來(lái)考慮退疫。

動(dòng)態(tài)類型語(yǔ)言(Javascript)

首先把不變的部分隔離出來(lái),那就是所有的動(dòng)物都會(huì)發(fā)出叫聲鸽素。

let makeSound = function(animal) {
  animal.sound();
}

然后把可變的部分各自封裝起來(lái)褒繁,也就是不同類型動(dòng)物的叫法。

let Duck = function() {};
Duck.prototype.sound = function() {
  console.log("嘎嘎嘎");
};

let Chicken = function() {};
Chicken.prototype.sound = function() {
  console.log("咯咯咯");
};

makeSound(new Duck());        // 嘎嘎嘎
makeSound(new Chicken());      // 咯咯咯

現(xiàn)在如果增加了一條狗馍忽,只要簡(jiǎn)單追加一些代碼就行了棒坏,不用改動(dòng)以前的 makeSound 函數(shù)。

靜態(tài)類型語(yǔ)言(Java)

靜態(tài)類型語(yǔ)言在編譯時(shí)會(huì)進(jìn)行類型匹配檢查遭笋。由于在代碼編譯時(shí)要進(jìn)行嚴(yán)格的類型檢查坝冕,所以不能給變量賦予不同類型的值。

要解決這一問(wèn)題瓦呼,歸根結(jié)底是先要消除類型之間的耦合關(guān)系喂窟。

如果類型之間的耦合關(guān)系沒(méi)有被消除,那么我們?cè)?makeSound 方法中指定了發(fā)出叫聲的對(duì)象是某個(gè)類型央串,它就不可能再被替換為另外一個(gè)類型磨澡,這一般是通過(guò)向上轉(zhuǎn)型來(lái)實(shí)現(xiàn)。

將 Duck 和 Chicken 不變的部分分隔開封裝到超類的抽象方法中质和,再分別讓兩者都繼承自抽象類 Animal稳摄。下述代碼中 (1) 和 (2) 處的賦值語(yǔ)句顯然是成立的,因?yàn)?Duck 和 Chicken 都是 Animal:

public abstract class Animal {
  abstract void makeSound();
}

public class Chicken extends Animal {
  public void makeSound() {
    System.out.println("咯咯咯");
  }
}

public class Duck extends Animal {
  public void makeSound() {
    System.out.println("嘎嘎嘎");
  }
}

Animal duck = new Duck();          // (1)
Animal chicken = new Chicken();    // (2)

剩下的就是讓 AnimalSound 類的 makeSound 方法接受 Animal 類型的參數(shù)饲宿,而不是具體的 Duck 類型或者 Chicken 類型:

public class AnimalSound {
  public void makeSound(Animal animal) {        // 接受抽象類的參數(shù)
    animal.makeSound();
  }
}

public class Test {
  public static void main(String args[]) {
    AnimalSound animalSound = new AnimalSound();
    Animal duck = new Duck();
    Animal chicken = new Chicken();
    animalSound.makeSound(duck);           // 嘎嘎嘎
    animalSound.makeSound(chicken);        // 咯咯咯
  }
}
兩者區(qū)別

多態(tài)思想實(shí)際上是把“做什么”和“誰(shuí)去做”分離開厦酬,要實(shí)現(xiàn)這一點(diǎn)胆描,歸根結(jié)底是先要消除類型之間的耦合關(guān)系。在靜態(tài)類型語(yǔ)言中仗阅,可以通過(guò)向上轉(zhuǎn)型來(lái)實(shí)現(xiàn)袄友。

而動(dòng)態(tài)類型語(yǔ)言的變量類型在運(yùn)行期是可變的。比如一個(gè) Javascript 對(duì)象霹菊,就既可以表示 Duck 類型的對(duì)象,又可以表示 Chicken 類型的對(duì)象支竹,這意味這動(dòng)態(tài)類型語(yǔ)言的多態(tài)是與生俱來(lái)的旋廷。這不難解釋,因?yàn)閯?dòng)態(tài)類型語(yǔ)言在編譯時(shí)沒(méi)有類型檢查的過(guò)程礼搁,所以不存在任何程度上的類型耦合饶碘,不需要向上轉(zhuǎn)型之類的技術(shù)來(lái)取得多態(tài)的效果。

設(shè)計(jì)模式與多態(tài)

在命令模式中馒吴,請(qǐng)求被封裝在一些命令對(duì)象中扎运,這使得命令的調(diào)用者和命令的接收者可以完全解耦開來(lái),當(dāng)調(diào)用命令的 execute 方法時(shí)饮戳,不同的命令會(huì)做出不同的事情豪治,從而會(huì)產(chǎn)生不同的執(zhí)行結(jié)果。而做這些事情的過(guò)程早已被封裝在命令對(duì)象內(nèi)部的扯罐,作為調(diào)用命令的客戶负拟,根本不必去關(guān)心命令執(zhí)行的具體過(guò)程。

在組合模式中歹河,多態(tài)性使得客戶可以完全忽略組合對(duì)象和葉節(jié)點(diǎn)對(duì)象之間的區(qū)別掩浙,這正是組合模式最大的作用所在。對(duì)組合對(duì)象和葉節(jié)點(diǎn)對(duì)象發(fā)出同一個(gè)消息的時(shí)候秸歧,它們會(huì)各自做自己應(yīng)該做的事情厨姚,組合對(duì)象把消息繼續(xù)轉(zhuǎn)發(fā)給下面的葉節(jié)點(diǎn)對(duì)象,葉節(jié)點(diǎn)對(duì)象則會(huì)對(duì)這些消息作出真實(shí)的反饋键菱。

在策略模式中谬墙,Context 并沒(méi)有執(zhí)行算法的能力,而是把這個(gè)職責(zé)委托給了某個(gè)策略對(duì)象经备。每個(gè)策略對(duì)象負(fù)責(zé)的算法已被各自封裝在對(duì)象內(nèi)部芭梯。當(dāng)我們對(duì)這些策略對(duì)象發(fā)出“計(jì)算”的消息時(shí),它們會(huì)返回各自不同的計(jì)算結(jié)果弄喘。

總結(jié)

Martin Fowler 在《重構(gòu):改善既有代碼的設(shè)計(jì)》里寫到:

多態(tài)最根本好處在于玖喘,你不必再向?qū)ο笤儐?wèn)“你是什么類型”而后根據(jù)得到的答案調(diào)用對(duì)象的某個(gè)行為——你只管調(diào)用該行為就是了,其它的一切多態(tài)機(jī)制都會(huì)為你安排妥當(dāng)蘑志。

換句話說(shuō)累奈,多態(tài)最根本的作用就是通過(guò)把過(guò)程化的分支語(yǔ)句轉(zhuǎn)化為對(duì)象的多態(tài)性贬派,從而消除這些條件分支語(yǔ)句

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末澎媒,一起剝皮案震驚了整個(gè)濱河市搞乏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌戒努,老刑警劉巖请敦,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異储玫,居然都是意外死亡侍筛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門撒穷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匣椰,“玉大人,你說(shuō)我怎么就攤上這事端礼∏菪Γ” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵蛤奥,是天一觀的道長(zhǎng)佳镜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)凡桥,這世上最難降的妖魔是什么邀杏? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮唬血,結(jié)果婚禮上望蜡,老公的妹妹穿的比我還像新娘。我一直安慰自己拷恨,他們只是感情好脖律,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腕侄,像睡著了一般小泉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冕杠,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天微姊,我揣著相機(jī)與錄音,去河邊找鬼分预。 笑死兢交,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的笼痹。 我是一名探鬼主播配喳,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼酪穿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了晴裹?” 一聲冷哼從身側(cè)響起被济,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涧团,沒(méi)想到半個(gè)月后只磷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泌绣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年钮追,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赞别。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖配乓,靈堂內(nèi)的尸體忽然破棺而出仿滔,到底是詐尸還是另有隱情,我是刑警寧澤犹芹,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布崎页,位于F島的核電站,受9級(jí)特大地震影響腰埂,放射性物質(zhì)發(fā)生泄漏飒焦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一屿笼、第九天 我趴在偏房一處隱蔽的房頂上張望牺荠。 院中可真熱鬧,春花似錦驴一、人聲如沸休雌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杈曲。三九已至,卻和暖如春胸懈,著一層夾襖步出監(jiān)牢的瞬間担扑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工趣钱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涌献,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓首有,卻偏偏與公主長(zhǎng)得像洁奈,于是被迫代替她去往敵國(guó)和親间唉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • 注:本文原名《OO NOT SUCKS, YOU DO》。 緣起 Erlang之父Joe Armstrong曾經(jīng)寫...
    _袁英杰_閱讀 8,094評(píng)論 11 36
  • 1.靜態(tài)語(yǔ)言和動(dòng)態(tài)語(yǔ)言靜態(tài)語(yǔ)言印叁,比如Java,是強(qiáng)類型的被冒,在編譯時(shí)就已經(jīng)確定好變量的類型,編譯器可以做一些性能優(yōu)化...
    Addy_Zhou閱讀 1,234評(píng)論 0 0
  • 面向?qū)ο蟮娜筇匦?封裝 繼承 多態(tài) python學(xué)習(xí)過(guò)程中轮蜕,封裝繼承將隨處可見昨悼,但卻很少遇見多態(tài),那么pytho...
    Sunnky閱讀 1,107評(píng)論 0 4
  • 面向?qū)ο缶幊逃腥筇匦裕悍庋b葱蝗、繼承、多態(tài)细燎。 封裝 封裝隱藏了類的內(nèi)部實(shí)現(xiàn)機(jī)制两曼,可以在不影響使用的情況下改變類的內(nèi)部...
    藍(lán)灰_q閱讀 419評(píng)論 0 0
  • 多態(tài),英語(yǔ)Polymorphism玻驻,由希臘語(yǔ)的兩個(gè)單詞polys(意為many, much)和morphē(意為f...
    法蘭克胡閱讀 571評(píng)論 0 2