iOS_设计模式学习:适配器模式

4,956 阅读4分钟

最近在学习《Objective-C编程之道:iOS设计模式解析》,本文是对适配器模式的一个分析和例子实现。

例子地址:Bryanthelol/iOS_DesignPattern

标签:接口适配


一、适配器模式是什么

用于连接两种不同种类的对象,使其毫无问题地协同工作

使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

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

二、如何实现适配器模式

两种方式实现:

  • 类适配器
  • 对象适配器

类适配器的实现

首先,我们来了解一下OC的一些特性:

Objective-C有协议,作为纯粹抽象的一种形式

在Objective-C中,类可以实现协议,同时又继承超类

因此,达到了多重继承的效果

然后,可以根据这些语言特性来实现适配器效果:

  1. 定义一套现在客户端将要使用的协议

  2. 再用一个适配器类实现这个协议

  3. 适配器类继承自被适配者(也就是那个与现有客户端不兼容的类)

关系图如下:

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自带的原生相册,功能不满足需求。

现在的需求则是:能多选图片,并且带有排序,也能单独编辑一张图片。就和微信发朋友圈时上传、编辑图片一样。

之后寻找了一个开源的图片编辑库IJSPhotoSDK,很好用很强大很好用。

现在的问题是,要把这个库放进项目里,但原则是尽量不改变调用者(就是上图,点击“上传图片”按钮的那个视图类)的代码。

这时候适配器模式就发挥了作用。


适配器CameraCall类

这个“弹出框”就放在CameraCall这个类,而CameraCall就是我们的主角——适配器。

回顾一下适配器的关系类图(这里使用对象适配器实现,因为需要适配多个Adaptee):

CameraCall适配器符合了这两个条件:

  • 它有一个CameraCallDelegate协议,供调用者签署然后实现

  • 它持有IJSPhotoSDK图片编辑库的实例

因此,IJSPhotoSDK图片编辑库的实例只需要调用自己的方法,返回图片数据,然后CameraCall适配器调用协议实例的方法,把数据返回给调用者“上传图片”按钮的那个视图类就可以了。

在视图类里实现CameraCallDelegate协议里的方法:

视图类不用关心是哪个图片编辑库的什么方法返回的数据,只关心协议方法返回的数据即可。

如果这时候,我们想换一个图片编辑库,就可以不改动调用者类的代码,只在CameraCall适配器里换成引入另一个图像编辑器,实例化这个编辑器,然后开始获取数据的操作就可以了。

可以看到,适配器模式本质上是把我们想要达成的这个“目的”抽象出来,放入这个叫适配器的对象中。这个对象进行一系列操作,使得调用者只需实现这个适配器对象即可,无需关心被适配者,就和现实中使用电源适配器一样。

最后我们的引入的图片多选编辑功能就完成了: