• 允许一个Adapter与多个Adaptee—即Adaptee本身以及它的所有子类(如果有子类的话)—同时工作。Adapter也可以一次给所有的Adaptee添加功能。
• 使得重定义Adaptee的行为比较困难。这就需要生成Adaptee的子类并且使得Adapter引用这个子类而不是引用Adaptee本身。
使用Adapter模式时需要考虑的其他一些因素有:
1) Adapter的匹配程度 对Adaptee的接口与Target的接口进行匹配的工作量各个Adapter可能不一样。工作范围可能是,从简单的接口转换(例如改变操作名 )到支持完全不同的操作集合。Adapter的工作量取决于Target接口与Adaptee接口的相似程度
2) 可插入的Adapter 当其他的类使用一个类时,如果所需的假定条件越少,这个类就更具可复用性。如果将接口匹配构建为一个类,
就不需要假定对其他的类可见的是一个相同的接口。也就是说,接口匹配使得我们可以将自己的类加入到一些现有的系统中去,
而这些系统对这个类的接口可能会有所不同。
3) 使用双向适配器提供透明操作 使用适配器的一个潜在问题是,它们不对所有的客户都透明。被适配的对象不再兼容 Adaptee的接口,
因此并不是所有 Adaptee对象可以被使用的地方它都可以被使用。双向适配器提供了这样的透明性。
在两个不同的客户需要用不同的方式查看同一个对象时,双向适配器尤其有用。
9. 实现
类适配器使用的是继承
让我们看看当API改变时,如何保护应用程序不受影响。
<?php /** * 类适配器模式 * @author guisu * */ /** * 目标角色 * @version 1.0 */ class Target { /** * 这个方法将来有可能改进 */ public function hello(){ echo 'Hello '; } /** * 目标点 */ public function world(){ echo 'world'; } } /** * Client 程序 * */ class Client { /** * Main program. */ public static function main() { $Target = new Target(); $Target->hello(); $Target->world(); } } Client::main(); ?>
我们Target已经明确指出hello()方法会在未来的版本中改进,甚至不被支持或者淘汰。接下来,现在假设第二版的Target已经发布。一个全新的greet()方法代替了hello()。
<?php /** * 类适配器模式 * @author guisu * */ /** * 目标角色 * @version 2.0 */ class Target { /** * 这个方法将来有可能继续改进 */ public function greet(){ echo 'Greet '; } /** * 目标点 */ public function world(){ echo 'world'; } }
如果我们继续使用原来的client代码,肯定会报错,找不到hello方法。
针对API“升级”的解决办法就是创建一个适配器(Adapter)。