《PHP設計模式介紹》第十三章 適配器模式(2)_PHP教程
推薦:《PHP設計模式介紹》第十二章 裝飾器模式若你從事過面向?qū)ο蟮膒hp開發(fā),即使很短的時間或者僅僅通過本書了解了一些,你會知道,你可以 通過繼承改變或者增加一個類的功能,這是所有面向?qū)ο笳Z言的一個基本特性。如果已經(jīng)存在的一個php
當?shù)玫降诙姹綡wLib的時候,你如何使它在第一版本HwLib的實例中體現(xiàn)?
| class HwLibV2ToV1Adapter { var $libv2; function HwLibV2ToV1Adapter (&$libv2) { $this->libv2 =& $libv2; } function hello() { return $this->libv2->greet(); } function world() { return $this->libv2->world(); } } |
HwLibV2ToV1Adapter::hello()方法代表了$libv2對象的greet()方法。
接著,你該如何在程序中使用它?
| class AdapterTestCase extends UnitTestCase { function TestOriginalAppWithAdapter() { $lib =& new HwLibV2ToV1Adapter(new HwLib); $this->assertEqual( ‘Greetings and Salutations World!’ ,$lib->hello().$lib->world()); } } |
剛才的程序測試和現(xiàn)在的程序代碼都有一定程度的脆弱性。有沒有方法在長久的使用中讓它們都更易于維護呢?當然是有的!
回憶一下(第三章)Factory是如何提供一個更靈活的方法來創(chuàng)建類的實例的。為了更好地在將來檢驗這些代碼,就從一個簡單的Factory函數(shù)開始:
| function &HwLibInstance() { return new HwLib; } |
為了測試Factory,直接調(diào)用它而不創(chuàng)建它的實例:
| class AdapterTestCase extends UnitTestCase { function TestAppWithFactory() { $lib =& HwLibInstance(); $this->assertWantedPattern( ‘/\w World!$/’ ,$lib->hello().$lib->world()); } } |
有兩個方面需要注意:Factory創(chuàng)建了對象,而用于確認的assertEqual()函數(shù)被修改為更靈活的assertWantedPattern()。你現(xiàn)在可以用一個正則表達式來捕獲你在庫中所要查找的“核心”,但可能會使這個測試本身變得脆弱。
接下來,升級HwLib庫。當安裝了HwLib第二版,你就可以修改HwLibInstance()函數(shù)來適應新的版本。
| function &HwLibInstance($ver=false) { switch ($ver) { case ‘V2’: return new HwLib; default: return new HwLibV2ToV1Adapter(new HwLib); } } |
現(xiàn)在重新運行AdapterTestCase。測試通過!(綠色進度條正常。)因為原始的程序沒有傳遞一個參數(shù),HwLibInstance會默認返回封裝在HwLibV2toV1Adapter中的HwLib的一個實例。盡管如此,如果你編寫了新的代碼,你可以傳遞進一個“V2”的參數(shù)讓這個函數(shù)自動選擇HwLib的新版本而不用去調(diào)整它。
以后,如果你選擇升級HwLib的第三版,應該將Factory做如下的調(diào)整:
| function &HwLibInstance($ver=false) { switch ($ver) { case ‘V3’: return new HwLib; case ‘V2’: return new HwLibV3ToV2Adapter(new HwLib); default: return new HwLibV2ToV1Adapter( new HwLibV3ToV2Adapter(new HwLib)); } } |
總結(jié)
如例中代碼所示,你可以運用適配器(Adapter)模式來避免因外部庫改變所帶來的不便——倘若向上兼容。作為某個庫的開發(fā)者,你應該獨立編寫適配器,使你的用戶更簡便地使用新版本的庫,而不用去修改他們現(xiàn)有的全部代碼。
GoF書中提出的適配器(Adapter)模式更傾向于運用繼承而不是組成。這在強類型語言中是有利的,因為適配器(Adapter)事實上是一個目標類的子類,因而能更好地與類中方法相結(jié)合。
下面是HwLib適配器運用繼承的范例:
class HwLibGofAdapter extends HwLib { // extending version 2.0
function hello() {
return parent::greet();
}
}
world()方法沒有在類中提到,因為運用了繼承,它已經(jīng)是子類的一部分。
class AdapterTestCase extends UnitTestCase {
function TestHwLibGofAdapter() {
$lib =& new HwLibGofAdapter;
$this->assertEqual(
‘Greetings and Salutations World!’
,$lib->hello().$lib->world());
}
}
為了更好的靈活性,我個人比較傾向于組成的方法(特別是在結(jié)合了依賴性倒置的情況下);盡管如此,繼承的方法提供兩種版本的接口,或許在你的實際運用中反而是一個提高靈活性的關鍵。
?注:依賴性倒置原理
依賴性倒置原理(首先在http://www.objectmentor.com/resources/articles/dip.pdf中由Robert C. Martin提出)是一個面向?qū)ο缶幊痰臏蕜t,它表明:高層次的模塊不應該依賴于低層次的模塊,而應依賴于抽取。一個簡單的與適配器(Adapter)模式相結(jié)合的依賴性倒置原理范例可以在以下地址中找到:
http://www.phplondon.org/wiki/DependencyInversion
適配器模式的重點是改變一個單獨類的API。有一個與之相關的設計模式(本書中沒有涵蓋),稱作正面(Facade)模式。正面(Facade)的目的是給由許多對象構(gòu)成的整個子系統(tǒng),提供更為簡潔的接口——反過來就是封裝一個單獨類——可能是一個值得研究的模式,如果你正設法把你的代碼與第三方庫隔離開來的話。
分享:《PHP設計模式介紹》第十一章 代理模式因為某個對象消耗太多資源,而且你的代碼并不是每個邏輯路徑都需要此對象, 你曾有過延遲創(chuàng)建對象的想法嗎 ( if和else就是不同的兩條邏輯路徑) ? 你有想過限制訪問某個對象,也就是說,提供一組方法
- 相關鏈接:
- 教程說明:
PHP教程-《PHP設計模式介紹》第十三章 適配器模式(2)
。