Mixin(織入)模式并不是GOF的《設(shè)計(jì)模式》歸納中的一種,但是在各種語(yǔ)言以及框架都會(huì)發(fā)現(xiàn)該模式(或者思想)的一些應(yīng)用。簡(jiǎn)單來(lái)說(shuō),Mixin是帶有全部實(shí)現(xiàn)或者部分實(shí)現(xiàn)的接口,其主要作用是更好的代碼復(fù)用。本文將介紹Mixin的應(yīng)用場(chǎng)景,以及關(guān)于繼承、組合、多繼承、接口的一些思考。

 

相關(guān)概念:

  前面提到,Mixin是有部分或者全部實(shí)現(xiàn)的接口,其主要作用是代碼復(fù)用,需要理解這個(gè)簡(jiǎn)單的描述,需要先理清一些概念。

繼承與組合:

  繼承是面向?qū)ο蟮娜筇卣鳎ǚ庋b、繼承、多態(tài)),如果類A繼承自類B,那么我們稱A為子類(派生類),稱B為父類(基類)。什么時(shí)候類A才能繼承類B呢,可以說(shuō)A是B的一種特殊化,英語(yǔ)來(lái)說(shuō)就是A is a B,或者A is a kind of B。比如狗(dog)和動(dòng)物(Animal)這兩個(gè)抽象,dog is animal,這個(gè)是成立的,所以dog可以繼承自animal。

  而組合代表的是其中一個(gè)類的對(duì)象是另一個(gè)類的對(duì)象的組成組合,英語(yǔ)來(lái)說(shuō),“has a”,比如人(People)這個(gè)類有一個(gè)屬性addr是一個(gè)地址類(Address)的實(shí)例,就是說(shuō)每個(gè)人都有一個(gè)地址。

  不管是繼承還是組合,都起到了代碼復(fù)用的作用,但又各有優(yōu)缺點(diǎn)。上面繼承和組合的例子都很明顯,但有些情況就不那么容易區(qū)分兩類事物是繼承還是組合的關(guān)系了,或者說(shuō),兩個(gè)類之間既可以用繼承,又可以用組合,比如設(shè)計(jì)模式中的adapter模式,既可以類適配,又可以組合適配(對(duì)象適配)。

 

多繼承與接口:

  在使用編程語(yǔ)言抽象事物之間的繼承關(guān)系的時(shí)候,需要考慮對(duì)多繼承的實(shí)現(xiàn)。所謂多繼承就是說(shuō)一個(gè)類有多個(gè)基類,舉個(gè)簡(jiǎn)單的例子,dog是animal,同時(shí)dog又是runnable(可以跑動(dòng)的對(duì)象)。多繼承對(duì)于人類的思維來(lái)說(shuō)是比較正常直觀的,但是對(duì)于計(jì)算機(jī)編程語(yǔ)言,都會(huì)遇到一個(gè)繞不過(guò)去的問(wèn)題,那就是菱形繼承(diamond problem),下面這個(gè)圖形象展示了什么時(shí)菱形繼承:

  大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

  從上圖可以看到,類B、類C都繼承了類A,類D同時(shí)繼承了類B和類C,在繼承關(guān)系上就形成了“菱形”--類D有兩條路徑到達(dá)類A。菱形問(wèn)題帶來(lái)什么問(wèn)題呢,如果類A定義了某個(gè)方法foo,而且B和C都沒(méi)有重寫該方法,那么B和C都會(huì)有某種機(jī)制找到foo,那么對(duì)于D的實(shí)例在調(diào)用foo方法的時(shí)候,是調(diào)用到B中指向的foo方法還是C中指向的foo方法呢?

  菱形繼承的問(wèn)題會(huì)影響到語(yǔ)言的設(shè)計(jì),一些編程語(yǔ)言支持多繼承,如C++、python等等;另外一些則不支持多繼承,如Java,ruby等。對(duì)于支持多繼承的語(yǔ)言,為了解決菱形繼承的問(wèn)題,一般都會(huì)使用特定的方法,比如C++中的虛繼承,python中的新式類的MRO。而對(duì)于不支持多繼承的語(yǔ)言,一般使用某種接口(或者約定、協(xié)議)來(lái)實(shí)現(xiàn)多繼承的功能,如Java中的interface,ruby中的include module。

 

duck typing:

  一個(gè)事物是不是鴨子(duck),如果