《PHP設(shè)計(jì)模式介紹》第十三章 適配器模式_PHP教程
推薦:《PHP設(shè)計(jì)模式介紹》第十二章 裝飾器模式若你從事過面向?qū)ο蟮膒hp開發(fā),即使很短的時(shí)間或者僅僅通過本書了解了一些,你會(huì)知道,你可以 通過繼承改變或者增加一個(gè)類的功能,這是所有面向?qū)ο笳Z言的一個(gè)基本特性。如果已經(jīng)存在的一個(gè)php
接口的改變,是一個(gè)需要程序員們必須(雖然很不情愿)接受和處理的普遍問題。程序提供者們修改他們的代碼;系統(tǒng)庫(kù)被修正;各種程序語言以及相關(guān)庫(kù)的發(fā)展和進(jìn)化。我孩子的無數(shù)玩具中有一個(gè)簡(jiǎn)要地描述了這個(gè)兩難局面:你無法合理安排一個(gè)不得其所的人。
問題
你如何避免因外部庫(kù)的API改變而帶來的不便?假如你寫了一個(gè)庫(kù),你能否提供一種方法允許你軟件的現(xiàn)有用戶進(jìn)行完美地升級(jí),即使你已經(jīng)改變了你的API?為了更好地適宜于你的需要,你應(yīng)該如何改變一個(gè)對(duì)象的接口?
解決方案
適配器(Adapter)模式為對(duì)象提供了一種完全不同的接口。你可以運(yùn)用適配器(Adapter)來實(shí)現(xiàn)一個(gè)不同的類的常見接口,同時(shí)避免了因升級(jí)和拆解客戶代碼所引起的糾紛。
考慮一下當(dāng)(不是假設(shè)!)一個(gè)第三方庫(kù)的API改變將會(huì)發(fā)生什么。過去你只能是咬緊牙關(guān)修改所有的客戶代碼,而情況往往還不那么簡(jiǎn)單。你可能正從事一項(xiàng)新的項(xiàng)目,它要用到新版本的庫(kù)所帶來的特性,但你已經(jīng)擁有許多舊的應(yīng)用程序,并且它們與以前舊版本的庫(kù)交互運(yùn)行地很好。你將無法證明這些新特性的利用價(jià)值,如果這次升級(jí)意味著將要涉及到其它應(yīng)用程序的客戶代碼。
注:控制體模式
適配器(Adapter)模式是控制體模式的最新范例。一個(gè)適配器(Adapter)的結(jié)構(gòu)類似于代理服務(wù)器(Proxy)和修飾器(Decorator),而它們的不同之處在于,適配器(Adapter)的目的是改變封裝類的接口,代理服務(wù)器(Proxy)和修飾器(Decorator)則是保持接口不變。
樣本代碼
讓我們看看當(dāng)API改變時(shí),如何保護(hù)應(yīng)用程序不受影響。
假設(shè)你費(fèi)盡心思尋找合適的庫(kù),最后終于找到了HwLib,一個(gè)(假設(shè)的)被設(shè)計(jì)用來發(fā)送信息的代碼集。
下面是HwLib類的源代碼:
| // PHP4 /** * the HwLib helps programmers everywhere write their first program * @package HelloWorld * @version 1 */ class HwLib { /** * Say “Hello” * @deprec this function is going away in the future * @return string */ function hello() { return ‘Hello ‘; } /** * target audience * @return string */ function world() { return ‘World!’; } } |
下面是庫(kù)運(yùn)行的范例:
| $hw =& new HwLib; echo $hw->hello(), $hw->world(); |
HwLib有完備的說明文檔。在文檔中作者已經(jīng)明確指出hello()方法會(huì)在未來的版本中不被支持(甚至淘汰)。
接下來,現(xiàn)在假設(shè)第二版的HwLib已經(jīng)發(fā)布。一個(gè)全新的greet()方法代替了hello()。
下面是這個(gè)庫(kù)的新版本(注釋已被抽取掉):
| // version 2 class HwLib { function greet() { return ‘Greetings and Salutations ‘; } unction world() { return ‘World!’; } } |
為了適應(yīng)HwLib的不同版本進(jìn)行編碼,先進(jìn)行一些基于第一版本HwLib接口的測(cè)試:
| class AdapterTestCase extends UnitTestCase { function TestOriginalApp() { $lib =& new HwLib; $this->assertEqual( ‘Hello World!’ ,$lib->hello().$lib->world()); } } |
你同樣可以表明,對(duì)這個(gè)庫(kù)的簡(jiǎn)單升級(jí)將造成此應(yīng)用程序的失效。
| class AdapterTestCase extends UnitTestCase { function TestOriginalAppWouldFail() { $lib =& new HwLib; // now using HwLib version 2 $this->assertFalse(method_exists($lib, ‘hello’)); } } |
(這個(gè)測(cè)試以method_exists()為例證。如果你簡(jiǎn)單地更換這個(gè)庫(kù)的第二版本并且以TestOriginalApp()的測(cè)試再次運(yùn)行AdapterTestCase,PHP就會(huì)運(yùn)行失敗,同時(shí)報(bào)告“致命錯(cuò)誤:未定義的函數(shù):hello()”)
針對(duì)API“升級(jí)”的解決辦法就是創(chuàng)建一個(gè)適配器(Adapter)。
第一步是獲得第二版本HwLib的實(shí)例的一個(gè)引用,并且把它加入到你的Adapter類中。
| class HwLibV2ToV1Adapter { var $libv2; function HwLibV2ToV1Adapter (&$libv2) { $this->libv2 =& $libv2; } } |
這個(gè)范例展示了將這個(gè)實(shí)例傳遞給構(gòu)造函數(shù)的過程,你也可以運(yùn)用Factory 或 Singleton ,或者其它適合你要求的創(chuàng)建模式,來創(chuàng)建一個(gè)新的實(shí)例。(通過前兩章,你應(yīng)該對(duì)HwLibV2ToV1Adapter的編寫用途很熟悉了)
分享:《PHP設(shè)計(jì)模式介紹》第十一章 代理模式因?yàn)槟硞(gè)對(duì)象消耗太多資源,而且你的代碼并不是每個(gè)邏輯路徑都需要此對(duì)象, 你曾有過延遲創(chuàng)建對(duì)象的想法嗎 ( if和else就是不同的兩條邏輯路徑) ? 你有想過限制訪問某個(gè)對(duì)象,也就是說,提供一組方法
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
- 相關(guān)鏈接:
- 教程說明:
PHP教程-《PHP設(shè)計(jì)模式介紹》第十三章 適配器模式
。