引言

  在项目开发中,有时候会遇到这样的一种情景:需要使用以前开发的“一些现存的对象”,但是新环境中要求的接口是这些现存对象所不满足的。怎样应对这种迁移的需求?使得可以复用这些对象,以满足新的应用环境,这就是适配器(Adapter)所要解决的问题。

定义

  “将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。”

  • 最初的定义出现于《设计模式》(Addison-Wesley,1994)。

  这个定义应该很好理解,生活中也到处充满着适配器模式的应用,比如说我们手机的充电器:手机是不能在220V电源上直接充电的,充电器将电压转换成手机需要的电压后,手机才可以正常充电,这个充电器就起到了适配的作用。

结构图

  有两种实现适配器模式的方式。第一种是通过继承来适配两个接口,这称为类适配器。在Gof介绍设计模式的书中,类适配器是通过多重继承来实现的。书中使用的语言是C++,它并没有C#的接口或OC的协议这样的语法,一切都是类。在OC中,类可以实现协议,同时又继承父类,达到C++多继承的效果。要在OC中实现类适配器,首先需要有定义了客户端要使用的一套行为的协议,然后要用具体的适配器类来实现这个协议。适配器类同时也要继承被适配者。类适配器结构图如下所示:

  从图中可以看到,Adapter是一个Target类型,同时也是Adaptee类型。它重载了Target的request方法,没有重载Adaptee中的specificRequest方法,而是在Adapter的request方法的实现中,调用父类的specificRequest方法。只有当Target是协议而不是类时,类适配器才能够用OC来实现,因为OC中是没有多重继承的

  实现适配器模式的第二种方式称为对象适配器。与类适配器不同,对象适配器不继承被适配者,而是组合了一个对它的引用。对象适配器结构图如下所示:

  从两个结构图可以看到,Target和Adapter的关系相同,Adapter和Adaptee之间的关系,由继承变成了关联。这种关系下,Adapter需要保持一个对Adaptee的引用。在request方法中,Adapter发送[_adaptee specificRequest]消息给Adaptee,以完成客户端的请求。

  很显然,OC中常用的委托(Delegate)模式属于对象适配器。以常用的UITableViewDelegate为例,我这里先画出它的结构图,如下所示:

  UITableView(对象适配器中的Client角色)处理选中行事件时,消息会传递给UITableViewDelegate(对象适配器中Target角色),然后调用MyViewController(对象适配器中Adapter角色)里面的- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath方法来进行处理,在MyViewController的这个方法中,我们会调用其他对象(比如说我们可能会调用详情DetailViewController对象来跳转到详情页面)来处理该消息。

示例

  示例使用结构图中的对象适配器和类适配器进行编写,阅读源码可以参看结构图,源码比较简单,这里就不做解说了。

  下载类适配器源码  下载对象适配器源码

小结

  适配器模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。

  适配器模式有对象适配器和类适配器两种形式的实现结构,但是类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用,另外,OC中也不支持多重继承。对象适配器采用“对象组合”的方式,更符合松耦合规范。

  在以下各种情况下可以考虑使用适配器模式:

  • 需要使用一个已经存在的类,而它的接口不符合新环境的规范。
  • 想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。

  返回目录

最新文章

  1. 1.Android 视图及View绘制分析笔记之setContentView
  2. 准备 LVM Volume Provider - 每天5分钟玩转 OpenStack(49)
  3. 通过单元测试理解spring容器以及dubbo+zookeeper单元测试异常处理
  4. 管道过滤器模式(Pipe and Filter)与组合模式(修改)
  5. Windows 10:解决开机显示C:\WINDOWS\system32\config\systemprofile\Desktop不可用的方法
  6. Random:产生随机数的类
  7. 动态规划:最长上升子序列(LIS)
  8. 14条Yahoo(雅虎)十四条优化原则【转】
  9. arttemplate函数摘录
  10. 图片文档倾斜矫正算法 附完整c代码
  11. python PEP8相关介绍
  12. 数据库性能优化(database tuning)性能优化绝不仅仅只是索引
  13. socketserver和socket的补充(验证客户端合法性)
  14. Spring用了哪些设计模式
  15. div展现与收起效果(鼠标移入移出)
  16. Paxos算法1-算法形成理论[转载]
  17. Maven基本介绍及安装
  18. 2015520吴思其 基于《Arm试验箱的国密算法应用》课程设计个人报告
  19. CSS框架960Grid从入门到精通一步登天
  20. 【tensorflow】pip 安装失败的原因

热门文章

  1. Java下List<Long>转List<String>或者List<Long>转List<Integer>
  2. 【ArcGIS 10.2新特性】ArcGIS 10.2将PostgreSQL原生数据发布为要素服务
  3. leetcode练习之No.1------ 两数之和Two Sum
  4. Jenkins任务优先分配到原来的执行节点上
  5. C语言中的联合体union所占内存方式
  6. 多重采样(MultiSample)下的FBO反锯齿 【转】
  7. gflops
  8. jquery怎样获得父级窗体的大小
  9. 【CI】系列二:Ubuntu环境虚拟机安装及配置
  10. unity3D打造skybox淡入淡出 - 移动开发