适配器模式
请选择一种我们课程中介绍的设计模式,用您熟悉的编程语言提供一个典型的应用范例,并分析其代码结构特性。完成一篇研究报告,具体要求如下:
- 引用关键代码(引用代码是为解释说明服务的,不要贴对解释问题无关的代码)解释该设计模式在该应用场景中的适用性;
- 引入该设计模式后对系统架构和代码结构带来了哪些好处;
- 解释其中用到的多态机制;
- 说明模块抽象封装的方法;
- 分析各个模块的内聚度和模块之间的耦合度;
- 提供该应用范例完整的源代码包括构建部署的操作过程,建议以github版本库URL的方式提供源代码,其中README.md中说明构建部署的操作过程。
适配器模式(adapter pattern)
1、定义
将⼀个类的接口转换成客户所希望的另外⼀ 个接口,适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。例如,各国使用的电压各不相同,有110V和220V等,但是我们的笔记本却可以直接使用。原因是电源适配器把电源转换成我们所需要的电压。
2、角色
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法。
适配器模式有:类适配器、对象适配器、接口适配器
(1)类适配器模式:原理-通过继承来实现适配器功能。
当我们要访问的接口A中没有我们要的方法 ,在另一个接口B中有该方法,我们又不能改变访问接口A,我们可以定义一个适配器p来进行中转,适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法,然后再继承接口B的实现类BB,这样我们可以在适配器P中访问接口B的方法了,这时我们在适配器P中的接口A方法中直接引用BB中的合适方法,这样就完成了一个简单的类适配器。
(2)对象适配器模式:原理-通过组合来实现适配器功能。
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法,然后在适配器P中定义私有变量C(对象)(B接口指向变量名),再定义一个带参数的构造器用来为对象C赋值,再在A接口的方法实现中使用对象C调用其来源于B接口的方法。
(3)接口适配器模式:原理-通过抽象类来实现适配。
当存在这样一个接口,其中定义了N多的方法,现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。适用的场景是不想实现原有类的所有方法
4、适配器模式应用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景:
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
接口适配器使用场景:
(1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。
5、案列分析
(1)类适配器
示例:在网上买了一个手机,但是买家给你发回来了一个3接头的充电器,但是恰好你又没有3接头的插槽,只有2个接口的插槽,于是便会想到去找你个3接口转两接口的转换器。这个转换器便是我们这里的适配器Adapter,已经存在的adaptee类是三相插头。
步骤一:Adaptee 原有的类 提供3接头
步骤二:Target 目标类 能插入2个接口,是抽象类
步骤三:类适配器,转换类 Adapter,使用多继承
运行结果如下:
(2)对象适配器
步骤一:Adaptee 原有的类 提供3接头
步骤二:Target 目标类 能插入2个接口,是抽象类
步骤三:对象适配器,转换类 Adapter,对象适配器相比类适配器来说更加灵活,他可以选择性适配自己想适配的对象。我们在构造的时候将具体需要适配的适配对象传入,这样便可以根据传入不同的对象,从而对该对象进行适配。而类适配器却无法选择对象,他是对整个类进行适配而不是针对某一个。
运行结果如下:
(3)接口适配器
缺省适配器模式是一种特殊的适配器模式,但这个适配器是由一个抽象类实现的,并且在抽象类中要实现目标接口中所规定的所有方法,但很多方法的实现都是“平庸”的实现,也就是说,这些方法都是空方法。而具体的子类都要继承此抽象类。
步骤一:抽象类,目标角色,在抽象类中要实现目标接口中所规定的所有方法
步骤二:具体的子类都要继承此抽象类,重写方法
步骤三:只需要通过DefaultAdapter适配器添加自己需要的操作
6、总结
(1)优点
复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。
低耦合:无需修改原有代码(遵循开闭原则)
(2)缺点
过多的使用适配器模式,会让系统难以把控,毕竟表面上是A接口,其实内部被适配成了B接口的实现。而且过多的使用适配器模式,代码的可阅读性会有所下降,但是设计模式应该是对于相对应的情况,而不是盲目的使用。
(3)对比
对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。 根据合成复用原则,组合大于继承, 所以它解决了类适配器必须继承的局限性问题,同样的它使用成本更低,更灵活。类适配器是类间继承,对象适配器是对象的合成关系,也可以说是类的关联关系,这是两者的根本区别。由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,而类适配器就只能通过覆写源角色的方法进行扩展。在实际项目中,对象适配器使用到的场景较多。
7、源代码地址:https://github.com/zzyangliu/ASE