模式概述
作用:
如果在系统中存在不兼容的接口,可以通过引入一个适配器来使原本因为接口不兼容,而不能在一起工作的两个类能够协同工作。定义:
适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口适配器模式,让那些接口不兼容的类可以一起工作。- 因为结构性模式可以描述两种不同的东西:类和类的实例(对象),根据这一点结构型模式可以分为
类结构性模式
和对象结构性模式
。 - 类结构型模式:关心类的组合,由多个类可以组合成一个更大的系统,所以在类结构型模式中一般只存在继承关系和实现关系。
- 对象结构型模式:关心类与对象的组合,通过关联关系在一个类中定义另一个类的实例对象,然后通过该调该对象调用相应的方法。
- 根据合成复用原则,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
模式结构
类适配器模式
Target
(目标抽象类):定义客户所需要的接口。Adapter
(适配器类):通过实现Target
接口并继承Adapter
类,使二者产生联系。Adaptee
(适配者类):适配者是被适配的角色,他定义了一个已经存在的接口,这个接口需要适配,适配者一般是一个具体类,包含了客户希望使用的业务方法。- 由于java不支持多重继承,所以没办法实现类适配器模式。
对象适配器模式
代码实现
需求:给移动的小汽车增加灯光闪烁和声音提示两个功能。
- 目标抽象类:
CarController
汽车控制类。
package com.daq.classAdapter;
/*
* 汽车控制类:充当抽象目标类
*/
public abstract class CarController {
public void move() {
System.out.println("玩具汽车移动");
}
public abstract void phonate();//发出声音
public abstract void twinkle();//灯光闪烁
}
- 适配者: 喇叭类 & 灯光类
package com.daq.classAdapter;
//喇叭类,充当适配者
public class PoliceSound {
public void alarmSound() {
System.out.println("发出警笛声音");
}
}
package com.daq.classAdapter;
//灯光类,充当适配者
public class PoliceLamp {
public void alarmLamp() {
System.out.println("灯光闪烁");
}
}
- 适配器类
package com.daq.classAdapter;
//适配器
public class PoliceCarAdapter extends CarController {
private PoliceSound sound; //定义适配者PoliceSound对象
private PoliceLamp lamp; //定义适配者PoliceLamp对象
//构造方法
public PoliceCarAdapter() {
sound=new PoliceSound();
lamp=new PoliceLamp();
}
//发出警笛声
@Override
public void phonate() {
sound.alarmSound(); //调用适配者类PoliceSound的方法
}
//灯光闪烁
@Override
public void twinkle() {
lamp.alarmLamp(); //调用适配者类PoliceLamp的方法
}
}
- 客户端测试类
package com.daq.classAdapter;
//客户端测试类
public class Client {
public static void main(String[] args) {
CarController car;
car=new PoliceCarAdapter();
car.move();
car.phonate();
car.twinkle();
}
}
- 如果需要增加其他的喇叭类或者灯光类,可以增加一个新的适配器类,使用新的适配器来适应新的声音类或者灯光类,原代码无需修改。只需要在客户端更换这个新的适配器类即可。
优缺点
优点:
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构。
- 增加类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者可以在多个不同的系统中复用。
缺点:
- 对于java,C#这种不支持多重继承的语言,一次最多只能适配一个适配者类。
- 适配者不可以是最终类,在java中不能是final类,
- 与类适配器模式相比,在该模式下要在适配器中置换适配者类的某些方法比较麻烦。
应用场景
- 系统需要使用一些现有的类,而这些类的接口(例如方法名)不符合系统的需要,甚至没有这些类的源代码。
- 想创建一个可以重复使用的类,用于和彼此之间没有太大关系的类(包括可能在将来引进的类)一起工作。