《PHP设计模式介绍》第十三章 适配器模式(2)_PHP教程

编辑Tag赚U币
教程Tag:暂无Tag,欢迎添加,赚取U币!

推荐:《PHP设计模式介绍》第十二章 装饰器模式
若你从事过面向对象的php开发,即使很短的时间或者仅仅通过本书了解了一些,你会知道,你可以 通过继承改变或者增加一个类的功能,这是所有面向对象语言的一个基本特性。如果已经存在的一个php

当得到第二版本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设计模式介绍》第十一章 代理模式
因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法

共2页上一页12下一页
来源:模板无忧//所属分类:PHP教程/更新时间:2008-08-22
相关PHP教程