大話設計模式:第17章 適配器模式

第17章:適配器模式

適配器模式

適配器模式(adapter):將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。

在軟件開發中,系統的數據和行爲都正確,但接口不符時,應該考慮用適配器,目的是使控制範圍之外的一個原有對象與某個接口匹配。適配器模式主要應用於希望複用一些現存的類,但是接口又與複用環境要求不一致的情況。

在這裏插入圖片描述

Target:客戶期待的接口,目標可以是具體類或抽象類,也可以是接口。

在這裏插入圖片描述

Adaptee:需要適配的類。

在這裏插入圖片描述

Adapter:通過在內部包裝一個Adaptee對象,把源接口轉換成目標接口。

在這裏插入圖片描述

客戶端代碼如下:

在這裏插入圖片描述

GoF《設計模式》講解了兩種適配器類型:類適配器模式對象適配器模式

類適配器模式:通過多重繼承對一個接口與另一個接口進行匹配。

在這裏插入圖片描述

對象適配器模式:將現有組件庫中已經實現的組件引入適配器類中,該類同時實現當前系統的業務接口。

在這裏插入圖片描述

適配器模式的使用

在使用一個已經存在的類時,如果它的接口(方法)和使用要求不相同時,即兩個類所做的事情相同或相似,但是具有不同的接口時,應該考慮用適配器模式。

由於類都共享同一個接口,使得客戶代碼可以統一調用同一接口,使代碼可以更簡單、更直接、更緊湊。

使用適配器模式屬於無奈之舉(亡羊補牢),通常在軟件開發後期或維護期,當雙方都不太容易修改的時候再考慮使用適配器模式適配。在設計階段,類和方法的命名應有規範,若接口不相同,首先應考慮通過重構統一接口,而非適配器。若設計子系統時考慮使用第三方開發組件,而該組件接口與自己的系統
接口不相同,則完全沒有必要爲了迎合該組件而改動自己的接口,此時儘管是在開發設計階段,也可以考慮用適配器模式來解決接口不同的問題。

注意事項

如果能事先預防接口不同問題,不匹配問題就不會發生;當小的接口不統一問題發生時,應及時重構,防止問題擴大;只有碰到無法改變原有設計和代碼的情況時,才考慮適配。事後控制不如事中控制,事中控制不如事前控制。

適配器模式的.NET應用

.NET中已經實現的適配器DataAdapter,用於DataSet和數據源之間的適配器以便檢索和保存數據。DataAdapter通過映射Fill(更改DataSet
中的數據以便與數據源中的數據相匹配)和Update(更改數據源中的數據以便與DataSet中的數據相匹配)提供適配器。

適配器模式示例

任務:籃球翻譯

在這裏插入圖片描述

from abc import ABC, abstractmethod
from typing import Text

class Player(ABC):
    """
    球員
    """
    def __init__(self, name: Text) -> None:
        self._name = name
        
    @abstractmethod
    def attack(self) -> None:
        pass
    @abstractmethod
    def defense(self) -> None:
        pass
    
class Forwards(Player):
    """
    前鋒
    """
    def __init__(self, name: Text) -> None:
        super(Forwards, self).__init__(name)
        
    def attack(self) -> None:
        print("前鋒%s進攻" % self._name)
        
    def defense(self) -> None:
        print("前鋒%s防守" % self._name)
        
class Center(Player):
    """
    中鋒
    """
    def __init__(self, name: Text) -> None:
        super(Center, self).__init__(name)
        
    def attack(self) -> None:
        print("中鋒%s進攻" % self._name)
        
    def defense(self) -> None:
        print("中鋒%s防守" % self._name)
        
class Guards(Player):
    """
    後衛
    """
    def __init__(self, name: Text) -> None:
        super(Guards, self).__init__(name)
        
    def attack(self) -> None:
        print("後衛%s進攻" % self._name)
        
    def defense(self) -> None:
        print("後衛%s防守" % self._name)
        
class ForeignCenter:
    """
    中鋒
    """
    def __init__(self) -> None:
        self._name = None
        
    @property
    def name(self) -> Text:
        return self._name
    @name.setter
    def name(self, name: Text) -> None:
        self._name = name
        
    def 進攻(self) -> None:
        print("中鋒%s進攻" % self._name)
        
    def 防守(self) -> None:
        print("中鋒%s防守" % self._name)
class Translator(Player):
    """
    翻譯者
    """
    def __init__(self, name: Text) -> None:
        super(Translator, self).__init__(name)
        self._foreigner = ForeignCenter()
        self._foreigner.name = name
        
    def attack(self) -> None:
        self._foreigner.進攻()
        
    def defense(self) -> None:
        self._foreigner.防守()
        
# 客戶端代碼

if __name__ == "__main__":
    
    player_b = Forwards("巴蒂爾")
    player_b.attack()
    
    player_m = Guards("麥克格雷迪")
    player_m.defense()
    
    player_y = Translator("姚明")
    player_y.attack()
    player_y.defense()
前鋒巴蒂爾進攻
後衛麥克格雷迪防守
中鋒姚明進攻
中鋒姚明防守
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章