源碼地址:https://github.com/weilanhanf/PythonDesignPatterns
說明:
為了解決接口不兼容的問題引進一種接口的兼容機制,就是適配器模式,其通過提供一種適配器類將第三方提供的接口轉換為客戶希望的接口。生活中的例子例如:手機充電器要將220v的電源轉換為手機適合的電壓才能充電。這個充電器就起到了適配的作用。
適配器模式:將一個類的接口轉換成客戶希望的另一個接口。適配器模式讓那些接口不兼容的類可以一起工作。適配器模式 別名為包裝器(Wrapper)模式 定義中所提及的接口是指廣義的接口,它可以表示一個方法或者方法的集合
適配器模式的結構
適配器模式包含以下3個角色: Target(目標抽象類) Adapter(適配器類) Adaptee(適配者類)
實例:
假設某公司A與某公司B需要合作,公司A需要訪問公司B的人員信息,但公司A與公司B協議接口不同,該如何處理?先將公司A和公司B針對各自的人員信息訪問系統封裝了對象接口。
class ACpnStaff: """ A公司 """ name="" id="" phone="" def __init__(self,id): self.id=id def getName(self): print("A protocol getName method...id:%s"%self.id) return self.name def setName(self,name): print("A protocol setName method...id:%s"%self.id) self.name=name def getPhone(self): print("A protocol getPhone method...id:%s"%self.id) return self.phone def setPhone(self,phone): print("A protocol setPhone method...id:%s"%self.id) self.phone=phone class BCpnStaff: """ B公司 """ name="" id="" telephone="" def __init__(self,id): self.id=id def get_name(self): print("B protocol get_name method...id:%s"%self.id) return self.name def set_name(self,name): print("B protocol set_name method...id:%s"%self.id) self.name=name def get_telephone(self): print("B protocol get_telephone method...id:%s"%self.id) return self.telephone def set_telephone(self,telephone): print("B protocol get_name method...id:%s"%self.id) self.telephone=telephone class CpnStaffAdapter: """ C公司 """ b_cpn="" def __init__(self,id): self.b_cpn=BCpnStaff(id) def getName(self): return self.b_cpn.get_name() def getPhone(self): return self.b_cpn.get_telephone() def setName(self,name): self.b_cpn.set_name(name) def setPhone(self,phone): self.b_cpn.set_telephone(phone) #業務場景 if __name__=="__main__": acpn_staff=ACpnStaff("123") acpn_staff.setName("X-A") acpn_staff.setPhone("10012345678") print("A Staff Name:%s"%acpn_staff.getName()) print("A Staff Phone:%s"%acpn_staff.getPhone()) bcpn_staff=CpnStaffAdapter("456") bcpn_staff.setName("Y-B") bcpn_staff.setPhone("99987654321") print("B Staff Name:%s"%bcpn_staff.getName()) print("B Staff Phone:%s"%bcpn_staff.getPhone())
打印結果:
A protocol setName method...id:123
A protocol setPhone method...id:123
A protocol getName method...id:123
A Staff Name:X-A
A protocol getPhone method...id:123
A Staff Phone:10012345678
B protocol set_name method...id:456
B protocol get_name method...id:456
B protocol get_name method...id:456
B Staff Name:Y-B
B protocol get_telephone method...id:456
B Staff Phone:99987654321
可以看出A類與B類的內部方法不一樣,也就是說無法使用一致的接口對A,B公司進行同時訪問,那么C類就應運而生。C類扮演的就是協議和接口轉化的適配器的角色,將B公司人員接口封裝,而對外接口形式與A公司人員接口一致,達到用A公司人員接口訪問B公司人員信息的效果。
模式優點
將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,無須修改原有結構 增加了類的透明性和復用性,提高了適配者的復用性,同一個適配者類可以在多個不同的系統中復用 靈活性和擴展性非常好 類適配器模式:置換一些適配者的方法很方便 對象適配器模式:可以把多個不同的適配者適配到同一個目標,還可以適配一個適配者的子類
模式缺點 類適配器模式:
(1) 一次最多只能適配一個適配者類,不能同時適配多個適配者;(2) 適配者類不能為最終類;(3) 目標抽象類只能為接口,不能為類 對象適配器模式:在適配器中置換適配者類的某些方法比較麻煩
模式適用環境
系統需要使用一些現有的類,而這些類的接口不符合系統的需要,甚至沒有這些類的源代碼 創建一個可以重復使用的類,用於和一些彼此之間沒有太大關聯的類,包括一些可能在將來引進的類一起工作
另外:
適配器模式和裝飾模式有一定的相似性,都起包裝的作用,但二者本質上又是不同的,裝飾模式的結果,是給一個對象增加了一些額外的職責,而適配器模式,則是將另一個對象進行了“偽裝”。適配器可以認為是對現在業務的補償式應用,所以,盡量不要在設計階段使用適配器模式,在兩個系統需要兼容時可以考慮使用適配器模式。