什麼是適配器模式?
適配器模式只是將某個物件的介面適配為另一個物件所期望的介面。
適配器模式應用問題與解決方案
在應用程式中,您也許會使用一個在體系結構上可靠且穩定的工作程式碼庫。不過我們常常會增加新的功能,這些功能要求採用不同的方式使用現有的對象,而不是採用原先設計的方式。此時,障礙可能只是新功能需要一個不同的名字。在較為複雜的場景中,障礙也可能是新功能需要與原始物件稍有不同的行為。
針對上述問題,我們採用的解決方案是使用適配器模式建立另一個物件。這個Adapter物件扮演了原始應用與新功能之間的中介。適配器模式為現有的物件定義了新的接口,從而能夠匹配新物件的要求。
問題
假設支付寶支付類別的功能如下:
/** * 支付宝支付类 */ class Alipay { public function sendPayment() { echo '使用支付宝支付。'; } } // 客户端代码 $alipay = new Alipay(); $alipay->sendPayment();
我們直接實例化Alipay類別完成支付功能,這樣的客戶端程式碼可能很多。
一段時間後,如果支付寶的Alipay類別升級,方法名稱由sendPayment()變成goPayment()會怎麼樣?
所有用了sendPayment()的客戶端程式碼都要改變。
如果Alipay類別頻繁升級,或是客戶端在很多地方使用,這會是極大的工作量。
解決
現在我們用適配器模式來解決。
我們在客戶端和Alipay類別之間加一個中間類,也就是適配器類,轉換原始的Alipay為客戶端所需的形式。
為讓客戶端能呼叫到統一的類別方法,我們先定義一個適配器介面:
/** * 适配器接口,所有的支付适配器都需实现这个接口。 * 不管第三方支付实现方式如何,对于客户端来说,都 * 用pay()方法完成支付 */ interface PayAdapter { public function pay(); }
因為Alipay類別我們無法控制,而且它有可能經常更新,所以我們不對它做任何修改。
我們新建一個AlipayAdapter適配器類,在pay()中轉換Alipay的支付功能,如下:
/** * 支付宝适配器 */ class AlipayAdapter implements PayAdapter { public function pay() { // 实例化Alipay类,并用Alipay的方法实现支付 $alipay = new Alipay(); $alipay->sendPayment(); } }
客戶端使用方式:
// 客户端代码 $alipay = new AlipayAdapter(); // 用pay()方法实现支付 $alipay->pay();
這樣,當Alipay的支付方法改變,只需要修改AlipayAdapter類別就可以了。
適應新類別
有了適配器後,擴充也變得更容易了。
繼續以上的例子,在支付寶的基礎上,我們再增加微信支付,它與支付寶的支付方式不同,必須透過掃碼才能支付。
這種情況也應該使用適配器,而不是直接使用微信的支付功能。
程式碼如下:
/** * 微信支付类 */ class WechatPay { public function scan() { echo '扫描二维码后,'; } public function doPay() { echo '使用微信支付'; } } /** * 微信支付适配器 */ class WechatPayAdapter implements PayAdapter { public function pay() { // 实例化WechatPay类,并用WechatPay的方法实现支付。 // 注意,微信支付的方式和支付宝的支付方式不一样,但是 // 适配之后,他们都能用pay()来实现支付功能。 $wechatPay = new WechatPay(); $wechatPay->scan(); $wechatPay->doPay(); } }
客戶端使用:
// 客户端代码 $wechat = new WechatPayAdapter(); // 也是用pay()方法实现支付 $wechat->pay();
這就是適配器的擴充特性。
我們創建了一個用於處理第三方類別(支付寶、微信支付)的方法,
如果它們的API有變化,我們只需修改客戶端依賴的適配器類別就可以,不用修改、揭露第三方類別本身。
UML圖
以上適配器模式的程式碼對應UML如下:
大的應用程式都會不斷地加入新函式庫和新API。
為避免它們的變更引發問題,應該用適配器模式包裝起來,提供應用統一的引用方式。
它會讓我們的程式碼更有結構化,方便管理和擴充。
以上是物件導向-設計模式:適配器模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!