设计模式 之 Adapter
简述
?????? 模式 Adapter(适配器)又称为 Wrapper(包装器),它的提出是为了协调那些功能可复用但接口格式不相称的代码场景。
?
第一个场景?????? 假设需要开发一款在线的电子白板软件,电子白板软件需要能够绘制各种图像及编辑文本。绘制功能对应的主要抽象是一组图像对象,如直线(LineShape)、矩形(RectangleShape)、 椭圆(OvalShape)、文本(TextShape)……,每个图像对象兼具图像算法和图像绘制职责。
?? ? ? 基础几何图像对象(如直线、矩形)是很容易实现的,但文本对象就比较复杂了,其中涉及到了文字格式、段落格式、屏幕更新、缓存管理等诸多内容。如果此时正好有一个成熟的文本绘制工具包可供使用,这个工具包中的TextView对象提供了完整的文本格式、段落、屏幕及缓存管理,实现了TextShape对象需要实现的一些职责。
?? ? ? 是否可复用呢?如何复用?
从TextView中硬拷贝代码显然是不可取的,先不说代码重复的问题,TextShape对象的实现本身会依赖同包中的其它代码,而这些代码又不全是对外权限公开的,如果把所依赖的私有代码再硬拷贝过来,那么所依赖的私有代码还会再依赖另外的私有代码,一生二,二生三,三生万物……这将是一场灾难。如果在工具包中直接修改TextView的代码就不会有权限问题了。但这种将上层逻辑移至底层依赖的做法是极其不推荐的。造成的结果是电子白板代码混乱、工具包代码混乱,而且对工具包中代码的直接修改很有可能引起工具包代码的本身不稳定。如果工具包的发布者提供了重要的版本升级,升级的内容也很难被引入到电子白板中。将TextView对象引入到TextShape中,在TextShape中酌情变通使用是可行的。这样做的问题在于TextShape中难免会出现一组为协调TextView和TextShape差异所写的代码,这样的代码会使TextView变形。?????? 既然这样,我们可以定义一个TextApapter对象,它负责TextView和TextShape之间的差异协调。TextShape用TextAdapter(继承或组合),TextAdapter用TextView(继承或组合)。关系如下图:?????? 这种结构,实际上就是Adapter模式。当然,如果TextAdapter本身需要做的事情很少,也可以直接用TextShape兼职Adaper。??
结构一、类适配器 && 对象适配器?????? 上例中通过继承实现Adaper模型(TextShape继承TextAdapter,TextAdapter继承TextView),也可以通过组合的方式实现。这两种方式也被称为Class Adapter(类适配器)和Object Adapter(对象适配器)。以下用类图描述这两种结构:


?
??????? 不同于类适配器,对象适配器使用的是组合的方式代替了继承(Adapter有指向Adaptee的引用,而不是Adapter继承Adaptee)。
?
?
?