聲明:本系列文章主要參考《精通Python設計模式》一書,並且參考一些資料,結合自己的一些看法來總結而來。
從本篇便開始介紹結構型設計模式,而適配器設計模式便是該類設計模式的一種,那么什么是結構型設計模式呢?
結構型設計模式:
其主要用來處理一個系統中不同實體(比如類和對象)之間關系,關注的是提供一種簡單的對象組合方式來創造新的功能。
適配器模式
該書中介紹主要為了適配器模式主要用於 幫助我們實現兩個不兼容接口之間的兼容。
當我們希望把一個老組件用於一個新組系統或者把一個新組件應用於老系統中,同時在代碼無法修改的,或者說無法訪問這些代碼時(在實際開發中,舊系統的代碼修改后牽一而動全身,很容易引起系統的崩潰。)。這時候,我們可以編寫一個額外的代碼層,該代碼層包含讓這兩個接口之間能夠通信需要進行的所有修改。
注:通俗的說就是設計 接口/API,以保證程序符合 開放/封閉 原則,同時保證不修改其他地方接口的調用方式,保持新老代碼間的兼容性。
示例:假設有這樣一個場景:
一、存在一套舊系統,里面包含 Computer類,如下:
class Computer: def __init__(self, name): self.name = name def __str__(self): return 'the {} computer'.format(self.name) def execute(self): return 'executes a program'
二、下面有需求,需要為該應用豐富更多的功能,而有了接下來的兩個類:Synthesizer、Human如下:
class Synthesizer: def __init__(self, name): self.name = name def __str__(self): return 'the {} synthesizer'.format(self.name) def play(self): return 'is playing an electronic song' class Human: def __init__(self, name): self.name = name def __str__(self): return '{} the human'.format(self.name) def speak(self): return 'says hello'
從上面代碼可以看出: Synthesizer 類,主要動作由play()方法執行。Human類主要動作由speak()方法執行。而原來的類 Computer其動作由execute()方法執行。
並且對於原來的老系統來說,所有動作函數均使用 Obj.execute() 來執行。即對於調用者來說,新系統的組件 Synthesizer.play() 和 Human.speak() 是不存在的,必須像調用 Computer.execute() 一樣使用 Synthesizer.execute() 和 Human.execute() 來調用原系統中對象的執行函數。
而這就是我們所說的常見,在無法修改 舊系統的調用方式和修改其源代碼的請求下,為了讓新組件去適應(兼容)舊系統的情況。所以這邊我們可以使用適配器模式來解決。
三、於是我們可以創建一個 通用的Adapter類,將一些帶不同接口的對象適配到一個統一接口中。
class Adapter: def __init__(self, obj, adapted_methods): self.obj = obj self.__dict__.update(adapted_methods) def __str__(self): return str(self.obj)
解析一下:
這里使用一個__init__魔法方法,將新組件的對象添加obj屬性中。而其中在__dict__魔法方法,將新組件對象的方法添加到適配器對象的屬性字典中。這樣就可以使用適配器對象即可調用新組件的方法。
四、接下來,只需要在調用時,對原有系統的類進行封裝,即可實現統一使用 execute() 方法執行動作了。代碼如下.
def main(): objects = [Computer('Asus')] synth = Synthesizer('moog') objects.append(Adapter(synth, dict(execute=synth.play))) human = Human('Bob') objects.append(Adapter(human, dict(execute=human.speak))) for i in objects: print('{} {}'.format(str(i), i.execute())) print('type is {}'.format(type(i)))
注釋:其實就是在實例化對象后,使用 Adapter 再將對象包裹一次,最終的調用其實都是調用了 Adapter 類的對象。即:調用適配器對象的execute方法其實就是調用 synth.play或者human.speak方法。
輸出結果如下:
the Asus computer executes a program type is <class '__main__.Computer'> the moog synthesizer is playing an electronic song type is <class '__main__.Adapter'> Bob the human says hello type is <class '__main__.Adapter'>
這也是為什么當我們執行下面代碼會報錯的原因:
for i in objects: print(i.name)
當然我們可以這樣改:
for i in objects: print(i.obj.name)
這樣就可以成功了。這是由於 i對象為適配器對象,只是它的屬性字典中,execute 其指向的為 Human.speak 的引用地址。故可以直接使用 i.execute() 進行調用。而其屬性字典中沒有 Human的name屬性,當然我們之前 將 human對象傳進來了,而其在適配器對象的obj屬性指向的是 human對象,故 i.obj.name 即可調用。
over~~~