[python] Mixin 掃盲班

來源:互聯網
上載者:User
 

Mixin 掃盲班賴勇浩(http://blog.csdn.net/lanphaday) 聲明:本文適合初中級Python程式員閱讀,另外本文措詞可能會導致閱讀者不適,敬請PG。  引子嗯,為什麼要談Mixin啊?因為出現了Mixin這樣一個東西呀,就像C++社區很多人談論template一樣啊,Python社區也很多會談論Mixin的(以後會的,嘻嘻),所以我就來湊湊熱鬧了。 嗯,為什麼要Mixin呀?這個,基本上已經是我這篇文章裡要講的東西了,所以,我會用本文的大部分篇幅來回答你這個超有深度的問題。現在,就開始吧~ 小時候,我家開百貨店,當然,也兼營水果蔬菜啊。小時候的事,總是特別有趣,也特別的有意義,所以今天我們就以水果店開始吧~ 記得,以前很多人買水果的時候,都會問我媽一個問題,就是價格了啦~但還有兩個問題也經常問到哦,就是送人應該買什麼水果和什麼水果可以用來送人? 嗯,年青人大多都不懂這些禮節。送水果也是很講兆頭的,比如梨和香蕉一般不用來送人,因為它們意味著離別和焦躁哦;而蘋果和桔子就很受歡迎,因為它們意味著平安和吉利哦~ 以此為開始那,這跟Python有什麼關係嗎?當然有啦,不然我扯那麼多皮幹嘛咧?現在,國產淩淩漆接到一個任務,要求他為一個水果連鎖店開發一套軟體;顯然這個不關心國計民生這些雞毛蒜皮的小事的武夫是搞不定這項艱巨任務的了,他就找到了你。 通過調研,客戶發現兩件事實:一是現在的年青人還是不懂送人應該買什麼水果和什麼水果可以用來送人這兩個問題;二是水果連鎖店的營業員100%都是年青人,他們也不懂。所以,客戶決定在軟體中必須提供一個這樣的功能--可以查詢一種水果是否適宜送人。最初,你可能這樣設計:class Fruit(object):       pass把fruit類作為一切水果的基類,嗯,這相當明智。代碼中去除了一些無需關注的代碼,如價格、產地等。現在你打算實現最受顧客歡迎的蘋果:class Apple(Fruit):       def is_gift_fruit(self):              return True同樣的,我又去除了一些無需關注的代碼,並且打算在接下來的行文中不再提醒這一點。Apple is a fruit。所以上面的實現挺符合OO的原則。接下來讓我們實現梨子吧:class Pear(Fruit):       def is_gift_fruit(self):              return False解決問題了。如果水果連鎖店只賣蘋果和梨子兩種水果的話。可惜,需求很多,你還要實現桔子和香蕉呢。你寫下了這幾行代碼:class Orange(Fruit):       def is_gift_fruit(self):              return Trueclass Banana(Fruit):       def is_gift_fruit(self):              return False好臭啊,代碼的壞味道!類apple和類Orange除了類名不同,幾乎是完全重複的代碼;類Pear和類Banana也是一樣。更進一層的說,這四個類都差不多啊,所以我們有必要重構一下已有代碼,改善它們的設計。 改善已有代碼閱讀代碼,你可以發現水果只分兩類:一類是可以作為禮品的,一類是不可以的。所以希望可以這樣設計:              Fruit              /      /       GiftFruit NotGiftFruit       /      /      /      /Apple        Orange Pear    Banana嗯,加了兩個中間類,看起來不錯:class GiftFruit(Fruit):       def is_gift_fruit(self):              return Trueclass NotGiftFruit(Fruit):       def is_gift_fruit(self):              return Falseclass Apple(GiftFruit):passclass Orange(GiftFruit):passclass Pear(NotGiftFruit):passclass Banana(NotGiftFruit):pass好啦,看上去很不錯哦,代碼精簡了不少,任務完成~ 新的煩惱接下來我們來完成另一項功能:提供水果食用方法諮詢。不要笑這個需求,這是真實的市場需求。比如相當部分一輩子生活在北方的朋友就沒有吃過龍眼荔枝香蕉;而南方雖然水果豐富,但不知道山竹等洋水果的也大有人在。我們這個水果連鎖店業務簡單,水果的食用方法也只分兩種:一種是剝皮的,如桔子和香蕉;另一種是削皮的,如蘋果和梨子。讓我們修改原有的設計:                     Fruit                     /      /              GiftFruit NotGiftFruit              /      /      /             /       PareG...   HuskG...     PareNot...     HuskNot...       /             /      /             /      Apple           Orange        Pear              Banana不得已,我們添加了四個類:class PareGiftFruit(GiftFruit):       def eat_method(self):              return 'Pare'class HustGiftFruit(GiftFruit):       def eat_method(self):              return 'Husk'class PareNotGiftFruit(NotGiftFruit):       def eat_method(self):              return 'Pare'class HuskNotGiftFruit(NotGiftFruit):       def eat_method(self):              return 'Husk'怎麼這四個類這麼像啊?汗。。。。先忍忍,把AOPB四種水果的實現改改:class Apple(PareGiftFruit):passclass Orange(HuskGiftFruit):passclass Pear(PareNotGiftFruit):Passclass Banana(HuskNotGiftFruit):pass我已經忍無可忍了。這個設計不僅僅又引入了好不容易消除的重複代碼,而且還修改了AOPB這四個類的實現。這種設計的擴充性也不好,如果以後要提供水果的其它特點,比如是進口水果還是國產水果。天啊,這還了得!加上這個特性,我要實現LocalPareGiftFruit、LocalHuskGiftFruit等類共8個(2的三次方)啊。水果的特徵多得很,隨便算算可能超過16種啊,65536個類?叫我去死吧~單是長達16個單詞的類名我就崩潰了!現在,你們都應該意識到這種實現方法實在是一種齷齪的設計了。那,我們應該怎麼樣設計呢? Pythonic的方案該是Mixin出場的時候了!先來看看Mixin的實現吧:class Fruit(object):       passclass GiftMixin(object):       def is_gift_fruit(self):              return Trueclass NotGiftMixin(object):       def is_gift_fruit(self):              return Falseclass PareMixin(object):       def eat_method(self):              return 'Pare'class HuskMixin(object):       def eat_method(self):              return 'Husk'class Apple(GiftMixin, PareMixin, Fruit):passclass Orange(GiftMixin, HuskMixin, Fruit):passclass Pear(NotGiftMixin, PareMixin, Fruit):passclass Banana(NotGiftMixin, HuskMixin, Fruit):pass編碼完成!這就是Mixin,就是這麼簡單,以致我無法再說出任何言語,因為我覺得上面的代碼已經完整地表達了我想要表達的思想。Mixin的好處是可以為主類(如Fruit)添加任意多的Mixin來實現多態,比如剛才說的水果有進口和國產兩個特徵,現在相當容易實現:class NativeMixin(object):       def Locality(self):              return 'Native'class ForeignMixin(object):       def Locality(self):              return 'Foreign'class Apple(ForeignMixin, GiftMixin, PareMixin, Fruit):pass #進口紅富士class Orange(NativeMixin, GiftMixin, HuskMixin, Fruit):passclass Pear(NativeMixin, NotGiftMixin, PareMixin, Fruit):passclass Banana(NativeMixin, NotGiftMixin, HuskMixin, Fruit):pass簡單多了,只加了兩個類,對AOPB的實現也只是增加了一個基類(增加總是勝過修改)。利用Mixin我們還可以增加無數總特徵,而無需對已有代碼作太大改動。 除此之外這時候,你可能會說:水果連鎖店軟體只是你杜撰的一個項目,Mixin有什麼實際用處嗎?當然有啦!其實Mixin並不是什麼高階的Python技巧,早有就很多開源項目使用這個技巧了,典型的,比如Python項目啊!在Python內建的SimpleServer.py裡就應用了Mixin來實現基於進程和基於線程的兩種TCP/UDP服務模型,在Tkinter和Python的其它模組也可以見到它的蹤跡,如果你留意的話。確切來說,我對Mixin來實現的水果連鎖店的實現仍然相當不滿意,但如果我們想要足夠物件導向,也就基本上只能接受如此解決方案了。如果有一天你不能忍受每增加一種特徵你就必須編寫N(N>=2)個Mixin,然後都必須給已經存在的AOPB代碼增加一個基類(想想,水果店賣的可不止四種水果,你會更頭大),那,就考慮把OO拋棄吧! 鳴謝在本文成文過程中,沈崴(http://eishn.blog.163.com)給我很大協助,特此鳴謝。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.