適配器模式是將目標對象的接口轉換爲使用者所期望的另外一個接口,使得原本接口類型不一致的類能夠更好的工作在一起。
使用場景:
兩個類所做的事情相同或相似,但是具有不同的接口時要使用它。客戶端可以統一調用同一接口,這樣應該可以更簡單、更直接、更緊湊。
一.需求提出
假設現在要求寫一個程序,這個程序示意一個足球對的訓練過程。這個足球隊有着中方球員、外援。由於語言文化不同。中方球員和外籍球員的控制接口是不一致的。
二.無設計的實現
`
# -*- coding: utf-8 -*-
class chinese_player:
def she_men(self):
print('射門!!!')
def fang_shou(self):
print('剷球!!!')
class foreign_player:
def shooting(self):
print('shoot Door!!!')
def defense(self):
print('Tackle!!!')
class coach:
def __init__(self, *team_plays):
self._players = team_plays
def trainning(self):
for player in self._players:
if isinstance(player, foreign_player):
player.shooting()
player.defense()
elif isinstance(player, chinese_player):
player.she_men()
player.fang_shou()
# 如果有更多的不同接口類型的球員,則需要寫更多的分支
if __name__ == '__main__' :
# 客戶端
wulei = chinese_player()
elkeson = foreign_player()
lipe = coach(wulei,elkeson)
lipe.trainning()
`
主要的問題:
1> 當程序需要擴展,需要處理更多類型的球員時,Coach 類的 trainning 函數需要不斷的去加分支。違反了開放封閉原則。
2> trainning中的isinstance接口,給人一個明顯的信號就是要識別具體的對象類型,根據具體的類型再做具體的操作。明顯的是依賴具體實現進行編程。違背了依賴倒置原則
附:
依賴倒置原則DIP(Dependency Inversion Principle):
高層模塊不應該依賴於低層模塊;二者都應該依賴於抽象。
抽象不應該依賴於細節;細節應該依賴抽象。
要針對接口編程,而不是針對實現編程。
單一職責原則SRP(Single Responsibility Principle):
就一個邏輯單元(類、函數)而言,應該僅有一個引起變化的原因。分離關注點;正交設計;
三.適配器模式重構
`
class chinese_player:
def she_men(self):
print('射門!!!')
def fang_shou(self):
print('剷球!!!')
class foreign_player:
def shooting(self):
print('shoot Door!!!')
def defense(self):
print('Tackle!!!')
class translater:
def __init__(self):
self._player = chinese_player()
def shooting(self):
self._player.she_men()
def defense(self):
self._player.fang_shou()
class coach:
def __init__(self, *team_plays):
self._players = team_plays
def trainning(self):
# 無需再對player的類型做具體的判斷和處理,針對shooting defense通用接口變成。
for player in self._players:
player.shooting()
player.defense()
if __name__ == '__main__':
# 爲中國球員請個洋翻譯:)
wulei = translater()
elkeson = foreign_player()
lipe = coach(wulei, elkeson)
lipe.trainning()
`
分析
1> translater類作爲一個適配器,實現了 she_men ->shooting fang_shou->defense 函數接口的映射,讓shooting 和 defense變爲通用函數接口。
2> 有了適配器的函數接口轉換,coach核心類的 trainning 接口,無需再做球員類型的具體判斷,只需要針對通用接口編程即可。後續的功能擴展,也無需再對training接口進行變更。