张子阳的博客

首页 读书 技术 店铺 关于
张子阳的博客 首页 读书 技术 关于

Adapter模式

2008-10-02 张子阳 分类: 设计与模式

生活中有很多Adapter的例子。比方说,你买了一款舒适、手感极佳的键盘,它是P/S接口的,然而你的新式电脑已经淘汰了P/S接口,只提供USB接口。此时,为了能够使用这款键盘,就需要一个转接头,它的一头是P/S接口的,用来连接键盘;另一头是USB的,用来连接电脑。类似这样的转接头就充当一个Adapter的作用。类似的例子还有电源的三相/两相 转接头等等。

 Adapter模式应该是设计模式中一个轻量级的模式,实现起来也比较简单,有时候不经意中,你可能就已经实现了一个Adapter模式,只是自己没有发现而已。本文将通过一个范例介绍 Adapter模式。

Shape范例

很多编程的书籍中都喜欢使用一个Shape作为范例讲述面向对象中的继承,尽管这里我们讲述的是Adapter模式,但是并不妨碍我们也使用这个Shape的例子。考虑下面一幅关系图:

在这幅图中,Shape抽象类定义了Draw()方法,用于在屏幕上绘制图形,Square和Circle继承了Shape类,并实现了Draw()方法。另一个与Shape相关联的类Window,它的Initialize()方法接受一个Shape类型的参数,并调用其Draw()方法(实际中还可能进行其他操作,这里的关键是方法的签名只接受一个Shape类型的参数)。

public void Initialize(Shape s)

现在考虑这样一种情况:假如我们从第三方获得了另一个类XTriangle,而它并没有Draw()方法,只有一个完成同样功能的Display()方法。很显然,这个类也不会继承自Shape基类,我们也无法对其进行修改。此时。如果我们想让客户程序Window类使用XTriangle类,就不得不再重载一个Initialize()方法,让它接受一个XTriangle类型的参数。但这是治标不治本的方法,因为可能有很多类似Window的类,它们都只接受Shape类型,对每一处都进行修改显然是不切实际的。此时,通常的办法是创建一个包装(Wrapper)类,让这个包装类继承自Shape,同时让它含有一个对XTriangle的引用,并且将Draw()方法的实现委托给XTriangle.Display()去完成。我们将这个包装类命名为Triangle,而这种模式或者解决类似问题的方法,就称为Adapter模式。注意在很多情况下我们会将Triangle命名为TriangleAdapter,但这里命名为Triangle会更清晰一些,但它仍是一个Adapter。下面是类图:

接下来我们看下来看一下Triangle的实现:

public class Triangle : Shape { private XTriangle triangle; public Triangle(XTriangle triangle) { this.triangle = triangle; } public override void Draw() { triangle.Display(); } }

OK,这样就实现了Adapter模式,它的正式定义是:将一个类(XTriangle)的接口转换为客户端(Window)所期待的另一接口(Shape)。Adpater能够让各个类之间相互协作,而不受不兼容接口的影响。

总结

这篇文章通过一个简短的范例演示了Adatper模式,通过创建一个包装类,解决了在引入第三方类时接口不兼容的问题。

感谢阅读,希望这篇文章能给你带来帮助!