文章目录
设计模式概述
创建型模式:工厂方法、抽象方法、建造者、原型、单例。
结构型模式有:适配器、桥接、组合、装饰器、外观、享元、代理。
行为型模式有:责任链、命令、解释器、迭代器、中介、备忘录、观察者、状态、策略、模板方法、访问者。
常用设计模式:
单例模式、工厂模式、代理模式、策略模式&模板模式、门面模式、责任链模式、装饰器模式、组合模式、builder模式。
1、适配器模式
-
适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。
-
这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
2、适配器模式的使用场景
-
假设有一部手机,它只能接受typec口输入或输出;还有一个投影仪,投影仪只能接受vga口作为输入或输出;现在,我们需要实现手机屏幕投影到投影仪上,可以通过创建一个适配器来实现:
- 目标接口:现有的投影仪只能接受vga口。
- 适配者类:手机的输出口为typec口。
- 适配器类:创建一个新的类,实现目标接口,并在内部使用适配者类来将视频信号从typec口输入,转换输出到vga口,才能和投影仪对接。
3、优点
- 促进了类之间的协同工作,即使它们没有直接的关联。
- 提高了类的复用性。
- 增加了类的透明度。
- 提供了良好的灵活性。
4、缺点
- 过度使用适配器可能导致系统结构混乱,难以理解和维护。
- 在Java中,由于只能继承一个类,因此只能适配一个类,且目标类必须是抽象的。
5、主要角色
- 目标接口(Target):定义客户需要的接口。
- 适配者类(Adaptee):定义一个已经存在的接口,这个接口需要适配。
- 适配器类(Adapter):实现目标接口,并通过组合或继承的方式调用适配者类中的方法,从而实现目标接口。
6、代码示例
1)UML图
2)源代码
(1)定义一部手机,它有个typec口。
/**
* @author jstao
* 定义一个手机Phone,它有一个Typec接口。
*
*/
public class Phone {
public void typecPhone() {
System.out.println("信息从Typec口的手机输出。");
}
}
(2)定义一个vga接口。
/**
* @author jstao
* 定义一个VGA接口。
*
*/
public interface Vga {
void vgaInterface();
}
(3)实现一个适配器,适配器实现方式分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
1】类的适配器模式(通过继承特性来实现适配器功能)
/**
*
* 实现一个Type-c转VGA适配器,
* 适配器实现方式有三种,这是第一种实现方式。
* @author jstao
*
*/
public class Typec2Vga1 extends Phone implements Vga{
@Override
public void vgaInterface() {
// TODO Auto-generated method stub
typecPhone();
System.out.println("接收到Type-c口信息,信息转换成VGA接口中...");
System.out.println("信息已转换成VGA接口,显示屏可以对接。");
}
}
2】对象的适配器模式(通过组合方式来实现适配器功能)
/**
*
* 实现一个Type-c转VGA适配器,
* 适配器实现方式有三种,这是第二种实现方式。
* @author jstao
*
*/
public class Typec2Vga2 implements Vga{
private Phone phone;
public Typec2Vga2(Phone phone) {
// TODO Auto-generated constructor stub
this.phone = phone;
}
@Override
public void vgaInterface() {
// TODO Auto-generated method stub
if(phone != null) {
phone.typecPhone();
System.out.println("接收到Type-c口信息,信息转换成VGA接口中...");
System.out.println("信息已转换成VGA接口,显示屏可以对接。");
}
}
}
3】接口的适配器模式(借助抽象类来实现适配器功能)
定义三个接口
/**
* 定义接口
* @author jstao
*
*/
public interface Target {
void typec();
void typec2vga();
void typec2hdmi();
}
定义一个抽象类
/**
* 定义一个抽象类
* @author jstao
*
*/
public abstract class Adapter implements Target{
public void typec() { }
public void typec2vga() { }
public void typec2hdmi() { }
}
实现一个vga适配器
/**
*
* 实现一个VGA适配器,同理还可以实现一个HDMI适配器
* 适配器实现方式有三种,这是第三种实现方式。
* @author jstao
*
*/
public class VgaAdapter extends Adapter{
public void typec() {
System.out.println("信息从Typec口的手机输出。");
}
public void typec2vga() {
System.out.println("接收到Type-c口信息,信息转换成VGA接口中...");
System.out.println("信息已转换成VGA接口,显示屏可以对接。");
}
}
(4)定义一个显示屏,用来测试上面实现的三个适配器。
/**
* 定义一个显示屏
* 与适配器对接
* @author jstao
*
*/
public class Screen {
public static void main(String[] args) {
//第一种适配器用法
System.out.println("-------------第一种适配器------------");
Vga vga = new Typec2Vga1();
vga.vgaInterface();//适配器将typec转换成vga
System.out.println("显示屏对接适配器,手机成功投影到显示屏!");
//第二种适配器用法
System.out.println("-------------第二种适配器------------");
Typec2Vga2 typec2Vga1 = new Typec2Vga2(new Phone());
typec2Vga1.vgaInterface();//适配器将typec转换成vga
System.out.println("显示屏对接适配器,手机成功投影到显示屏!");
//第三种适配器用法
System.out.println("-------------第三种适配器------------");
VgaAdapter vgaAdapter = new VgaAdapter();
vgaAdapter.typec();
vgaAdapter.typec2vga();//适配器将typec转换成vga
System.out.println("显示屏对接适配器,手机成功投影到显示屏!");
}
}
7、总结
-
适配器模式在源码中的应用:
- (1)JDK源码的IO模块用到,例如 java.io.InputStreamReader(InputStream)、java.io.OutputStreamWriter(OutputStream)。
- (2)mybatis源码日志模块用到对象适配器模式。
-
适配器模式将一个接口转为另外一个接口。它有三种实现方式:
-
(1)当希望将一个类转换为满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
-
(2) 当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Typec2Vga2 类,持有原类的一个实例,在Typec2Vga2 类的方法中,调用实例的方法就行。
-
(3)当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法,我们写别的类的时候,继承抽象类即可。
-