最近在学习《Objective-C编程之道:iOS设计模式解析》,本文是对适配器模式的一个分析和例子实现。
例子地址:
标签:接口适配
一、适配器模式是什么
用于连接两种不同种类的对象,使其毫无问题地协同工作
使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
适配器模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
二、如何实现适配器模式
两种方式实现:
- 类适配器
- 对象适配器
类适配器的实现
首先,我们来了解一下OC的一些特性:
Objective-C有协议,作为纯粹抽象的一种形式
在Objective-C中,类可以实现协议,同时又继承超类
因此,达到了多重继承的效果
然后,可以根据这些语言特性来实现适配器效果:
定义一套现在客户端将要使用的协议
再用一个适配器类实现这个协议
适配器类继承自被适配者(也就是那个与现有客户端不兼容的类)
关系图如下:
Adapter继承了Target协议的接口method方法,然后重载了method方法。在method方法中,Adapter继承了Adaptee,但没有重载specificMethod方法,而是直接调用超类specificMethod方法,在Adapter自己的环境下运行。
对象适配器的实现
对象适配器不继承被适配器,即Adapter不继承Adaptee。而是用对象组合:Adapter持有一个Adaptee的实例引用。
关系图如下:
和类适配器的区别是:
- Adapter和Adaptee之间的关系从“继承”变成了“包含”
- 这种关系下,Adapter需要保持一个对Adaptee的实例引用
在method方法中,Adapter通过adaptee实例,间接调用specificMethod方法,在Adapter自己的环境下运行。
类适配器和对象适配器的区别对比
-
类适配器:
- 只针对单一的具体的Adaptee类,把Adaptee适配到Target
- 易于重载Adaptee的行为,因为是通过直接的子类化进行的适配
- 只有一个Adapter对象,无需额外的指针间接访问Adaptee
-
对象适配器:
- 可以适配多个Adaptee及其子类
- 难以重载Adaptee的行为,需要借助于子类的对象而不是Adaptee本身
- 需要额外的指针以间接访问Adaptee并适配其行为
三、用我自己的样例代码讲解
在我现在的项目里,正好有一个例子。
情况是这样,如图:
点击了“添加图片”按钮后,会弹出下面的“拍照上传”“从相册选择”选项,暂且称作“弹出框”吧。
现在的问题是,“从相册选择”出现的选择图片界面,图片只能被单选:
就像上面两张图展示的一样,选择一张照片后,就只能点确定了。其实就是使用了iOS自带的原生相册,功能不满足需求。
现在的需求则是:能多选图片,并且带有排序,也能单独编辑一张图片。就和微信发朋友圈时上传、编辑图片一样。
之后寻找了一个开源的图片编辑库,很好用很强大很好用。
现在的问题是,要把这个库放进项目里,但原则是尽量不改变调用者(就是上图,点击“上传图片”按钮的那个视图类)的代码。
这时候适配器模式就发挥了作用。
适配器CameraCall类
这个“弹出框”就放在CameraCall这个类,而CameraCall就是我们的主角——适配器。
回顾一下适配器的关系类图(这里使用对象适配器实现,因为需要适配多个Adaptee):
CameraCall适配器符合了这两个条件:
- 它有一个CameraCallDelegate协议,供调用者签署然后实现
- 它持有IJSPhotoSDK图片编辑库的实例
因此,IJSPhotoSDK图片编辑库的实例只需要调用自己的方法,返回图片数据,然后CameraCall适配器调用协议实例的方法,把数据返回给调用者“上传图片”按钮的那个视图类就可以了。
在视图类里实现CameraCallDelegate协议里的方法:
视图类不用关心是哪个图片编辑库的什么方法返回的数据,只关心协议方法返回的数据即可。
如果这时候,我们想换一个图片编辑库,就可以不改动调用者类的代码,只在CameraCall适配器里换成引入另一个图像编辑器,实例化这个编辑器,然后开始获取数据的操作就可以了。
可以看到,适配器模式本质上是把我们想要达成的这个“目的”抽象出来,放入这个叫适配器的对象中。这个对象进行一系列操作,使得调用者只需实现这个适配器对象即可,无需关心被适配者,就和现实中使用电源适配器一样。
最后我们的引入的图片多选编辑功能就完成了: