[Python設計模式] 第22章 手機型號&軟件版本——橋接模式

github地址:https://github.com/cheesezh/python_design_patternspython

緊耦合程序演化

題目1

編程模擬如下情景,有一個N品牌手機,在上邊玩一個小遊戲。git

class HandsetNGame():
    
    def run(self):
        print("運行N品牌手機遊戲")
        
def main():
    game = HandsetNGame()
    game.run()
    
main()
運行N品牌手機遊戲

題目2

如今又有一個M品牌的手機,也有小遊戲,客戶端也能夠調用,須要如何改?github

from abc import ABCMeta, abstractmethod


class HandsetGame():
    __metaclass__ = ABCMeta
    
    @abstractmethod
    def run(self):
        pass
    

class HandsetNGame(HandsetGame):
    
    def run(self):
        print("運行N品牌手機遊戲")
        
        
class HandsetMGame(HandsetGame):
    
    def run(self):
        print("運行M品牌手機遊戲")

點評

如今不一樣的手機又要增長通信錄功能,又要如何改?編程

那就意味着父類應該是「手機品牌」,下有「手機品牌M」和「手機品牌N」,每一個子類下邊又各有「通信錄」和「小遊戲」。從上到下是個1-2-4的層級結構。設計模式

若是這樣的話,那增長一款新的軟件,須要在每一個手機品牌下邊都實現一次,若是新增長一款手機品牌,又須要把全部軟件都重寫一次。設計

繼承不必定好?

對象的繼承關係在編譯時就定義好了,因此沒法在運行時改變從父類繼承的實現。子類的實現與它的父類有很是緊密的依賴關係,以致於父類實現中的任何變化都必然會致使子類發生變化。但你須要複用子類時,若是繼承下來的實現不適合解決新的問題,則父類必須重寫或者被其餘更合適的類替換。這種依賴關係限制了靈活性並最終限制了複用性[DP]。code

合成/聚合複用原則

合成/聚合複用原則,儘可能使用合成/聚合,儘可能不要使用類繼承。對象

聚合表示一種弱的「擁有」關係,體現的是A對象能夠包含B對象,可是B對象不是A對象的一部分,就如同「大雁」和「雁羣」;繼承

合成表示一種強的「擁有」關係,體現了嚴格的部分和總體的關係,部分和總體的生命週期同樣,就如同「吃飽」和「大雁」;生命週期

優先使用對象的合成/聚合將有助於保持每一個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物[DP]。

像「遊戲」,「通信錄」等功能都是軟件,咱們應該讓其與手機解耦,也就是再弄一個「手機軟件」抽象類。

鬆耦合的程序

from abc import ABCMeta, abstractmethod


class HandsetSoft():
    __metaclass__ = ABCMeta
    
    @abstractmethod
    def run(self):
        pass
    
    
class HandsetGame(HandsetSoft):
    
    def run(self):
        print("run handset game")
        
        
class HandsetAddressList(HandsetSoft):
    
    def run(self):
        print("run handset address list")
        
        
class HandsetBrand():
    __metaclass__ = ABCMeta
    
    @abstractmethod
    def run(slef):
        pass
    
    def set_handset_soft(self, soft):
        self.soft = soft
        
        
class HandsetBrandN(HandsetBrand):
    
    def run(self):
        print("on handset brand N")
        self.soft.run()
        
        
class HandsetBrandM(HandsetBrand):
    
    def run(self):
        print("on handset brand M")
        self.soft.run()
        
        
def main():
    brand = HandsetBrandN()
    brand.set_handset_soft(HandsetGame())
    brand.run()
    
    brand.set_handset_soft(HandsetAddressList())
    brand.run()
    
    brand = HandsetBrandM()
    brand.set_handset_soft(HandsetGame())
    brand.run()
    
    brand.set_handset_soft(HandsetAddressList())
    brand.run()
    
main()
on handset brand N
run handset game
on handset brand N
run handset address list
on handset brand M
run handset game
on handset brand M
run handset address list

點評

如今若是要增長音樂播放器,那麼只要增長這個類就行,不影響其餘任何類。

class HandsetPlayer(HandsetSoft):
    
    def run(self):
        print("run handset player")

如今若是要增長手機品牌S,也只須要增長一個品牌子類便可。

這顯然也符合了咱們以前的開放-封閉原則,這樣的設計顯然不會修改原來的代碼,只要擴展類便可。

繼承也是一種強耦合的結構,因此優先使用對象的合成或聚合,而不是類繼承。

像「手機軟件」和「手機品牌」兩個抽象類之間進行關聯,使得它們的實現部分互相分類,就好像一座橋同樣,這就是橋接模式。

橋接模式

橋接模式,將抽象部分與它的實現部分分離,使它們能夠獨立地變化。[DP]

將抽象部分和實現部分分離,並非指讓抽象類和派生類分離,而是指抽象類和它的派生類用來實現本身的對象。就像剛剛的手機品牌&手機軟件之間的關係,既能夠按照品牌進行實現,又能夠按照軟件分類進行實現。因爲實現的方式有多種,橋接模式的核心意圖就是把這些實現獨立出來,讓它們各自的變化。這使得每種實現的變化都不會影響其餘實現,從而達到應對變化的目的。

面對真實需求,實現系統可能有多角度分類,每一種分類均可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減小它們之間的耦合。

在咱們須要多角度去分類實現對象,而只用繼承會形成大量的類增長,不能知足開放-封閉原則時,就應該考慮使用橋接模式了。

只要真正深刻理解設計原則,不少設計模式其實就是原則的應用而已,或許在不經意間就在使用設計模式了。

相關文章
相關標籤/搜索