程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python 設計模式:適配器模式

編輯:Python

適配器模式是一種結構型設計模式, 它能使接口不兼容的對象能夠相互合作。通過組合對象的方式來創建新功能。

什麼是適配器


適配器幫助我們使兩個不兼容的接口兼容。這到底是什麼意思呢?如果我們有一個舊的組件,我們想在一個新的系統中使用它,或者我們想在一個舊的系統中使用一個新的組件。兩者很少能在不需要修改代碼的情況下進行交流。
但是,改變代碼並不總是可能的,要麼是因為我們無法訪問它,要麼是因為它不切實際。在這種情況下,我們可以寫一個額外的層,對兩個接口之間的通信進行一些必要的修改,在兩個接口之間實現通信。
這個層被稱為適配器。

適配器的作用


適配器不僅可以轉換不同格式的數據, 其還有助於采用不同接口的對象之間的合作。 它的運作方式如下:
  • 適配器實現與其中一個現有對象兼容的接口。
  • 現有對象可以使用該接口安全地調用適配器方法。
  • 適配器方法被調用後將以另一個對象兼容的格式和順序將請求傳遞給該對象。

有時你甚至可以創建一個雙向適配器來實現雙向轉換調用。

真實世界的例子


  • 不同國家的電源插頭和插座標准不同。 美國插頭和德國插座不匹配。 同時提供美國標准插座和歐洲標准插頭的電源適配器可以解決你的難題。當你從大多數歐洲國家到英國或美國旅行,你需要使用電源適配器為你的筆記本電腦充電。
  • 不同的電子產品的適配接口也不一樣,比如相機和手機的接口不同。當你使用不同的電子產品,需要不同讀取數據的接口:USB、HDMI、VGA 等接口。

適配器模式結構

對象適配器
當我們的 client 想要打開風扇,而風扇提供了 turnOn 方法,直接調用 turnOn 即可享受涼爽的風,比如下圖:
然後同樣是打開的操作,client 想通過 turnOn 調用打開電視機,而電視機沒有這個方法,電視機提供的 open 方法。如果我們直接把 open 方法改為 turnOn 的方法,可能會引發系統的一系列其他問題,這個時候就需要我們的適配器模式了。
客戶端可以會使用各種各樣的適配器,為了方便保存,可以為適配器抽象出一個接口,UML 圖如下:

適配器 (Adapter) 是一個可以同時與客戶端和服務交互的類: 它在實現客戶端接口的同時封裝了服務對象。 適配器接受客戶端通過適配器接口發起的調用, 並將其轉換為適用於被封裝服務對象的調用。
客戶端代碼只需通過接口與適配器交互即可, 無需與具體的適配器類耦合。 因此, 你可以向程序中添加新類型的適配器而無需修改已有代碼。 這在服務類的接口被更改或替換時很有用: 你無需修改客戶端代碼就可以創建新的適配器類。
代碼如下:public interface IAdapter {
 public void turnOn(); // 通用開機函數
}

public class Tv {
 public void open() {
 System.out.println("電視機 TV 開機,只能使用 open 函數");
 }
}

public class TvAdapter extends Tv implements IAdapter {
 public void turnOn() {
 super.open(); // 適配器模式
 }
}

調用方式:public class Main {
 public static void main(String[] args) {
 IAdapter adapter = new TvAdapter();
 adapter.turnOn();
 }
}

類適配器
這一實現使用了繼承機制: 適配器同時繼承兩個對象的接口。 請注意, 這種方式僅能在支持多重繼承的編程語言中實現, 例如 C++。

Python 實現

class Target:
 """
 The Target defines the domain-specific interface used by the client code.
 """

 def request(self) -> str:
 return "Target: The default target's behavior."


class Adaptee:
 """
 The Adaptee contains some useful behavior, but its interface is incompatible
 with the existing client code. The Adaptee needs some adaptation before the
 client code can use it.
 """

 def specific_request(self) -> str:
 return ".eetpadA eht fo roivaheb laicepS"


class Adapter(Target, Adaptee):
 """
 The Adapter makes the Adaptee's interface compatible with the Target's
 interface via multiple inheritance.
 """

 def request(self) -> str:
 return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}"


def client_code(target: "Target") -> None:
 """
 The client code supports all classes that follow the Target interface.
 """

 print(target.request(), end="")


if __name__ == "__main__":
 print("Client: I can work just fine with the Target objects:")
 target = Target()
 client_code(target)
 print("\n")

 adaptee = Adaptee()
 print("Client: The Adaptee class has a weird interface. "
 "See, I don't understand it:")
 print(f"Adaptee: {adaptee.specific_request()}", end="\n\n")

 print("Client: But I can work with it via the Adapter:")
 adapter = Adapter()
 client_code(adapter)

運行該程序:Client: I can work just fine with the Target objects:
Target: The default target's behavior.

Client: The Adaptee class has a weird interface. See, I don't understand it:
Adaptee: .eetpadA eht fo roivaheb laicepS

Client: But I can work with it via the Adapter:
Adapter: (TRANSLATED) Special behavior of the Adaptee.

適配器模式優缺點

優點:
  •  單一職責原則你可以將接口或數據轉換代碼從程序主要業務邏輯中分離。
  •  開閉原則。 只要客戶端代碼通過客戶端接口與適配器進行交互, 你就能在不修改現有客戶端代碼的情況下在程序中添加新類型的適配器。
缺點:
  •  代碼整體復雜度增加, 因為你需要新增一系列接口和類。 有時直接更改服務類使其與其他代碼兼容會更簡單。

參考鏈接:
  • 適配器模式
  • 漫畫面向對象編程:16.13 適配器模式:傲嬌的電器

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved