PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

PHP设计模式介绍 第十三章 适配器模式

PHP设计模式介绍 第十三章 适配器模式

来源:互联网  作者:  发布时间:2010-05-22
接口的改变,是一个需要程序员们必须(虽然很不情愿)接受和处

当得到第二版本HwLib的时候,你如何使它在第一版本HwLib的实例中体现?

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());
}
}

刚才的程序测试和现在的程序代码都有一定程度的脆弱性。有没有方法在长久的使用中让它们都更易于维护呢?当然是有的!

回忆一下(第三章)Factory是如何提供一个更灵活的方法来创建类的实例的。为了更好地在将来检验这些代码,就从一个简单的Factory函数开始:

function  &HwLibInstance()  {
return  new  HwLib;
}

为了测试Factory,直接调用它而不创建它的实例:

class  AdapterTestCase  extends  UnitTestCase  {
function  TestAppWithFactory()  {
$lib  =&  HwLibInstance();
$this->assertWantedPattern(
‘/\w+  World!$/’
,$lib->hello().$lib->world());
}
}

有两个方面需要注意:Factory创建了对象,而用于确认的assertEqual()函数被修改为更灵活的assertWantedPattern()。你现在可以用一个正则表达式来捕获你在库中所要查找的“核心”,但可能会使这个测试本身变得脆弱。

接下来,升级HwLib库。当安装了HwLib第二版,你就可以修改HwLibInstance()函数来适应新的版本。

function  &HwLibInstance($ver=false)  {
switch  ($ver)  {
case  ‘V2’:
return  new  HwLib;
default:
return  new  HwLibV2ToV1Adapter(new  HwLib);
}
}

现在重新运行AdapterTestCase。测试通过!(绿色进度条正常。)因为原始的程序没有传递一个参数,HwLibInstance会默认返回封装在HwLibV2toV1Adapter中的HwLib的一个实例。尽管如此,如果你编写了新的代码,你可以传递进一个“V2”的参数让这个函数自动选择HwLib的新版本而不用去调整它。

以后,如果你选择升级HwLib的第三版,应该将Factory做如下的调整:

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));
}
}

总结

如例中代码所示,你可以运用适配器(Adapter)模式来避免因外部库改变所带来的不便——倘若向上兼容。作为某个库的开发者,你应该独立编写适配器,使你的用户更简便地使用新版本的库,而不用去修改他们现有的全部代码。

GoF书中提出的适配器(Adapter)模式更倾向于运用继承而不是组成。这在强类型语言中是有利的,因为适配器(Adapter)事实上是一个目标类的子类,因而能更好地与类中方法相结合。

下面是HwLib适配器运用继承的范例:

class  HwLibGofAdapter  extends  HwLib  {  //  extending  version  2.0
function  hello()  {
return  parent::greet();
}
}

world()方法没有在类中提到,因为运用了继承,它已经是子类的一部分。

class  AdapterTestCase  extends  UnitTestCase  {
function  TestHwLibGofAdapter()  {
$lib  =&  new  HwLibGofAdapter;
$this->assertEqual(
‘Greetings  and  Salutations  World!’
,$lib->hello().$lib->world());
}
}

为了更好的灵活性,我个人比较倾向于组成的方法(特别是在结合了依赖性倒置的情况下);尽管如此,继承的方法提供两种版本的接口,或许在你的实际运用中反而是一个提高灵活性的关键。

?注:依赖性倒置原理

依赖性倒置原理(首先在http://www.objectmentor.com/resources/articles/dip.pdf中由Robert  C.  Martin提出)是一个面向对象编程的准则,它表明:高层次的模块不应该依赖于低层次的模块,而应依赖于抽取。一个简单的与适配器(Adapter)模式相结合的依赖性倒置原理范例可以在以下地址中找到:

http://www.phplondon.org/wiki/DependencyInversion

适配器模式的重点是改变一个单独类的API。有一个与之相关的设计模式(本书中没有涵盖),称作正面(Facade)模式。正面(Facade)的目的是给由许多对象构成的整个子系统,提供更为简洁的接口——反过来就是封装一个单独类——可能是一个值得研究的模式,如果你正设法把你的代码与第三方库隔离开来的话。


延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式
PHP设计模式介绍 第七章 策略模式
PHP设计模式介绍 第八章 迭代器模式

PHP设计模式介绍 第九章 观测模式
PHP设计模式介绍 第十章 规范模式
PHP设计模式介绍 第十一章 代理模式
PHP设计模式介绍 第十二章 装饰器模式
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号