1 初步认识
适配器模式的定义
将一个类的接口转成客户期望的另外一个接口. 适配器模式使得原本由于接口不匹配而不能一起工作的那些类可以一起工作.
大白话
适配器模式就像旅行插座转换器 (图 1),Type-c 转 VGA 转接口(图 4) 一样.
图 1. 图片来源网络
图 2. 图片来源网络
去过香港迪拜等的同学都知道, 那边用的插座跟我们不一样, 他们的插座需要如图 2 第 1 面所示的插头, 而我们常用的插座类似第 2 面. 因此我们的笔记本电脑, 手机在当地不能直接充电. 所以就需要一个插座转换器, 转换器第 1 面插入当地的插座, 第 2 面供我们充电, 这样使得我们的插头在当地能使用. Type-c 转 VGA 转接口也是一样的道理.
2 适配器模式结构图
图 3. 适配模式结构图 来源网络
如图所示, Client 不能直接访问 Adaptee.Adapter 是适配器, 它将 Adaptee 转换成 Client 能访问的接口. 所以通过适配器 Adapter, 用户端就可以访问 Adaptee.
3 使用场景例子
手机想要投影到投影仪上, 由于手机是 Type-c 接口, 投影仪是 VGA 接口. 不能直接投影, 需要一个适配器, 将视频信号从 Type-c 口转到 VGA 口, 最后才能输出到大屏幕上.
4 适配器模式在使用场景的具体实现
图 4. typec 转 vga/hdm 转换器
如图所示, 这有一个适配器, 一号口是 typec 口, 二号口是 vga 口, 只有将视频信号从 typec 口输入, 转换输出到 vga 口, 才能和投影仪对接, 实现手机屏幕投影到投影仪上的任务. 涉及的物品有: 手机, 适配器, 投影仪.
4.1 定义一个手机, 它有个 typec 口, 这是视频源.
- package com.jstao.adapter;
- /**
- * @author jstao
- * 定义一个手机 Phone, 它有一个 Typec 接口.
- *
- */
- public class Phone {
- public void typecPhone() {
- System.out.println("信息从 Typec 口的手机输出.");
- }
- }
4.2 定义一个 vga 接口
- package com.jstao.adapter;
- /**
- * @author jstao
- * 定义一个 VGA 接口.
- *
- */
- public interface Vga {
- void vgaInterface();
- }
4.3 实现一个适配器, 适配器实现方式分三类: 类的适配器模式, 对象的适配器模式, 接口的适配器模式.
4.3.1 类的适配器模式
原理: 通过继承特性来实现适配器功能.
- package com.jstao.adapter;
- /**
- *
- * 实现一个 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 接口, 显示屏可以对接.");
- }
- }
4.3.2 对象的适配器模式
原理: 通过组合方式来实现适配器功能.
- package com.jstao.adapter;
- /**
- *
- * 实现一个 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 接口, 显示屏可以对接.");
- }
- }
- }
4.3.3 接口的适配器模式
原理: 借助抽象类来实现适配器功能.
定义三个接口
- package com.jstao.adapter;
- /**
- * 定义接口
- * @author jstao
- *
- */
- public interface Target {
- void typec();
- void typec2vga();
- void typec2hdmi();
- }
定义一个抽象类
- package com.jstao.adapter;
- /**
- * 定义一个抽象类
- * @author jstao
- *
- */
- public abstract class Adapter implements Target{
- public void typec() { }
- public void typec2vga() { }
- public void typec2hdmi() { }
- }
实现一个 VGA 适配器
- package com.jstao.adapter;
- /**
- *
- * 实现一个 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.4 定义一个显示屏, 用来测试上面实现的三个适配器
- package com.jstao.adapter;
- /**
- * 定义一个显示屏
- * 与适配器对接
- * @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("显示屏对接适配器, 手机成功投影到显示屏!");
- }
- }
4.5 测试结果
图 5. 结果输出图
可以看到, 得到的结果都一样, 但是三种适配器的实现的方式却不相同.
5 小结
5.1 适配器模式在源码中的应用:
(1)JDK 源码的 IO 模块用到, 例如 java.io.InputStreamReader(InputStream),java.io.OutputStreamWriter(OutputStream).
(2)mybatis 源码日志模块用到对象适配器模式.
5.1 适配器模式将一个接口转为另外一个接口. 它有三种实现方式:
(1)当希望将一个类转换为满足另一个新接口的类时, 可以使用类的适配器模式, 创建一个新类, 继承原有的类, 实现新的接口即可, 例如 4.3.1.
(2) 当希望将一个对象转换成满足另一个新接口的对象时, 可以创建一个 Typec2Vga2 类, 持有原类的一个实例, 在 Typec2Vga2 类的方法中, 调用实例的方法就行, 例如 4.3.2 对象的适配器模式.
(3)当不希望实现一个接口中所有的方法时, 可以创建一个抽象类 Adapter , 实现所有方法, 我们写别的类的时候, 继承抽象类即可, 例如 4.3.3 接口的适配器模式.
6 我的其他 JAVA 设计模式
(1)JAVA 设计模式之策略模式
(2)JAVA 设计模式之观察者模式
来源: https://www.cnblogs.com/luohanguo/p/10334291.html