目录
- 结构型模式
- 适配器模式概述
- 适配器模式的结构与实现
- 适配器模式的应用实例
- 缺省适配器模式
- 双向适配器模式
- 适配器模式的优缺点与适用环境
结构型模式
结构型模式(Structural Pattern)关注如何将现有类或对象组织在一起形成更加强大的结构。不同的结构型模式从不同的角度组合类或对象,它们在尽可能满足各种面向对象设计原则的同时为类或对象的组合提供一系列巧妙的解决方案
类结构型模式
- 关心类的组合,由多个类组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系
对象结构型模式
- 关心类与对象的组合,通过关联关系,在一个类中定义另一个类的实例对象,然后通过该对象调用相应的方法
结构型模式一览表:
适配器模式概述
电源适配器,现实生活:
- 不兼容:生活用电220V ßà 笔记电脑20V
- 引入 AC Adapter(交流电适配器)
软件开发:
- 存在不兼容的结构,例如方法名不一致
- 引入适配器模式
适配器模式的定义:
- 适配器模式:将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
- Adapter Pattern: Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
- 对象结构型模式 / 类结构型模式
注:
- 别名为包装器(Wrapper)模式
- 定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合
适配器模式的结构与实现
适配器模式的结构(类适配器)
模式分析:根据类适配器模式结构图,在类适配器中,适配者类Adaptee没有request方法,而客户端期待这个方法,但在适配者类中实现了specificRequest方法,该方法所提供的实现正是客户所需要的。为了使客户能够使用适配者类,我们提供了一个中间类,即适配器类Adapter,适配器类实现了抽象目标类接口,并继承了适配器类,在适配器类的request方法中调用所继承的适配器类的specificRequest方法,实现适配的目的。因为适配器类与适配者类是继承关系,所以这种适配器模式称为类适配器模式。
经典代码如下:
public class Adapter extends Adaptee implements Target {
public void request {
specificRequest();
}
}
适配器模式的结构(对象适配器)
模式分析:根据类适配器模式结构图,在类适配器中,适配者类Adaptee没有request方法,而客户端期待这个方法,但在适配者类中实现了specificRequest方法,该方法所提供的实现正是客户所需要的。为了使客户能够使用适配者类,我们提供了一个包装类,即适配器类Adapter。这个包装类包装了一个适配者的实例,从而将客户端与适配者衔接起来,在适配器的request方法中调用适配者的specificRequest方法。因为适配器类与适配者类是关联关系,所以这种适配器模式称为对象适配器模式。
经典代码如下;
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void request() {
adaptee.specificRequest();
}
}
适配器模式包含的角色如下:
Target(目标抽象类)
目标抽象类定义客户端要用的特定领域的接口,可以是一个抽象类或接口,也可以是一个具体的类。在类适配器中,由于Java语言不支持多重继承,它只能是接口。
Adapter(适配器类)
适配器类可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类Adapter是适配器模式的核心。在类适配器中,它通过实现Target接口并继承Adaptee类来使二者产生联系。在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类)
适配者类即被适配的角色,它定义一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下甚至没有适配者类的源代码。
Client(客户类)
在客户端类中针对目标类进行编程,调用在目标类中定义的业务方法。
适配器模式的应用实例
在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找,该系统的设计人员已经开发了一个成绩操作接口ScoreOperation,在该接口中声明了排序方法Sort(int[]) 和查找方法Search(int[], int),为了提高排序和查找的效率,开发人员决定重用现有算法库中的快速排序算法类QuickSortClass和二分查找算法类BinarySearchClass,其中QuickSortClass的QuickSort(int[])方法实现了快速排序,BinarySearchClass的BinarySearch (int[], int)方法实现了二分查找。
由于某些原因,开发人员已经找不到该算法库的源代码,无法直接通过复制和粘贴操作来重用其中的代码;而且部分开发人员已经针对ScoreOperation接口编程,如果再要求对该接口进行修改或要求大家直接使用QuickSortClass类和BinarySearchClass类将导致大量代码需要修改。
现使用适配器模式设计一个系统,在不修改已有代码的前提下将类QuickSortClass和类BinarySearchClass的相关方法适配到ScoreOperation接口中。
实例类图
实例代码
- ScoreOperation:抽象成绩操作类,充当目标接口
- QuickSortClass:快速排序类,充当适配者
- BinarySearchClass:二分查找类,充当适配者
- OperationAdapter:操作适配器,充当适配器
- 配置文件App.config
- Program:客户端测试类
结果及分析
- 将具体适配器类的类名存储在配置文件App.config中
- 扩展方便
缺省适配器模式
定义:缺省适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。
结构:
实现
缺省适配器类的典型代码片段:
public abstract class AbstractSeviceClass implments ServiceInterface {
public void serviceMethod1();
public void serviceMethod2();
public void serviceMethod3();
}
双向适配器模式
结构:
双向适配器经典代码片段:
public class Adapter implements Target, Adaptee {
//同时维持对抽象目标类和适配者的引用
private Target target;
private Adaptee adaptee;
public Adapter(Target target) {
this.target = target;
}
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void Request() {
adaptee.SpecificRequest();
}
public void SpecificRequest() {
target.Request();
}
}
适配器模式的优缺点与适用环境
模式优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构
- 增加了类的透明性和复用性,提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用
- 灵活性和扩展性非常好
- 类适配器模式:置换一些适配者的方法很方便
- 对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类
模式缺点
- 类适配器模式:(1) 一次最多只能适配一个适配者类,不能同时适配多个适配者;(2) 适配者类不能为最终类;(3) 目标抽象类只能为接口,不能为类
- 对象适配器模式:在适配器中置换适配者类的某些方法比较麻烦
模式适用环境
- 系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码
- 创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作