结构型模式关注如何将现有类或对象组织一起形成更加强大的结构。
一、概述
适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作。
二、结构
- Target(目标抽象类):
定义客户所需接口,可以是抽象类 / 接口、具体类,类适配器只能使用接口。 - Adapter(适配器类):
可以调用 另一个接口,作为一个转换器,对Adaptee 和 Target 进行适配。 - Adaptee(适配者类):
被适配的角色,定义了一个已经存在、需要适配的接口,包含业务方法。
类适配器:
适配者类 Adaptee 没有 request() 方法,而使用者期望该方法,适配者类并无该方法。定义适配器类 Adapter 实现 Target 接口,并继承 适配者类 Adaptee 从而解决该问题。在适配者类的 request() 方法中调用所继承的适配者类 specialRequest() 方法,以达到目的:
public class Adapter extends Adaptee implements Target {
@Override
public void request(){
super.specialRequest();
}
}
对象适配器:
对象适配器与类适配器类似,不同的点在于:类适配器通过类继承特性,达到目的;而对象适配器则采用 组合 / 聚合方式完成兼容:
public class Adapter extends Target{
private Adaptee adaptee; //维持一个对适配者对象的引用
//构造器:初始化
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void request(){
adaptee.specialRequest(); //转发调用
}
}
三、举例
我们以 对象适配器 为例,应用至以下场景:
警车在移动过程中伴随警灯闪烁、警笛鸣笛,现在已经实现了 警灯闪烁、警笛鸣笛 的代码,须重用该代码,并使得控制软件具有更好的灵活性、可扩展性。
实例代码:
汽车控制类:充当 目标抽象类:
//汽车控制类:负责控制汽车运转
public abstract class CarController {
//车移动
public void move(){
System.out.println("警车移动!");
}
//预留方法:闪灯、鸣笛
public abstract void phonate();
public abstract void twinkle();
}
警笛类:充当 适配者:
//警笛类:负责警车鸣笛
public class PoliceSound {
//鸣笛方法
public void alarmSound(){
System.out.println("警笛鸣笛!");
}
}
警灯类:充当 适配者:
//警灯类:负责警灯闪烁
public class PoliceLamp {
//闪灯方法
public void alarmLamp(){
System.out.println("警灯闪烁!");
}
}
警车 (适配) 类:充当 适配器:
//警车类:适配器类
public class PoliceCar extends CarController{
private PoliceSound sound;
private PoliceLamp lamp;
//无参数构造器:自动初始化
public PoliceCar() {
this.sound = new PoliceSound();
this.lamp = new PoliceLamp();
}
//全参数构造器:初始化
public PoliceCar(PoliceSound sound, PoliceLamp lamp) {
this.sound = sound;
this.lamp = lamp;
}
@Override
public void phonate() {
this.sound.alarmSound();
}
@Override
public void twinkle() {
this.lamp.alarmLamp();
}
}
测试代码:
try{
CarController car;
car = (CarController) Class.forName("com.simple.PoliceCar").getDeclaredConstructor().newInstance();
car.move();
car.phonate();
car.twinkle();
}catch (Exception e){
e.printStackTrace();
}
四、特点
☯ 优点
共同优点:
- 目标者类与适配者类解耦,引入适配器类重用适配者类。
- 使用适配者类封装业务,可在不影响原有结构的条件下,反复复用该类。
- 较好的灵活性、扩展性,完全符合开闭原则。
类适配优点:
- 适配器类是适配者子类,可重写适配者方法,使得适配器更加灵活。
对象适配优点:
- 一个对象适配器可适配多个适配者,不受单继承体系的影响。
- 根据里氏转换原则,可适配已适配的适配者子类。
☯ 缺点
类适配缺点:
- 单继承体系使得适配数量受限
- 适配者类不能为final类
- 目标抽象类仅能为接口
对象适配缺点:
- 该模式下,要在适配器中替换适配者类的某些方法比较麻烦,若需实现,可定义一已重写适配者类方法的子类,并对其进行适配,使得类结构更复杂。