设计模式 – 适配器模式详解
- 2020 年 3 月 27 日
- 筆記
适配器模式
生活中,充电插头有两脚的、三脚的,还有圆形的,如果想使这些插头都能工作,就需要一个多功能适配器
基本介绍
适配器模式(Adapter Pattern)属于结构性模式,它可以将某个类的接口转换为客户端期望的另一个接口表示,主要目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作,其别名为包装器(Wrapper)。适配器模式主要分为三类:类适配器模式、对象适配器模式、接口适配器模式。
工作原理
- 让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是解耦的
- 用户调用适配器转化出来的目标接口方法,适配器去再调用被适配者的相关接口方法
类适配器模式
实现原理
Adapter 类继承 src 类,实现 dst 接口,完成 src 对 dst 的适配。
案例
插座(Voltage220V)的输出电压是220V,充电插头(Voltage5V)输出电压是5V,这时候就需要一个适配器(VoltageAdapter)转换电压,才能给手机(Phone)充电
代码实现
电源输出电压为220V
public class Voltage220V { public int output220V() { int src = 220; System.out.println("电源输出" + src + "V"); return src; } }
充电器输出电压为5V
public interface Voltage5V { int output5V(); }
适配器需要将220V转为5V
public class VoltageAdapter extends Voltage220V implements Voltage5V { @Override public int output5V() { int src = super.output220V(); int dst = src / 44; System.out.println("转换为" + dst + "V"); return dst; } }
手机接收5V电压,判断电压是否为5V
public class Phone { public static void charging(Voltage5V voltage5V){ int v = voltage5V.output5V(); if(v == 5){ System.out.println("接收电压为5V,正常充电"); }else if(v > 5){ System.out.println("电压高于5V,无法充电"); } } }
测试方法
@Test public void test01(){ System.out.println("====类适配器模式===="); Phone.charging(new VoltageAdapter()); }
运行结果
====类适配器模式==== 电源输出220V 转换为5V 接收电压为5V,正常充电
分析
- 由于 Java 是单继承机制,所以类适配器模式有一定的局限性
- src 类的方法再 Adapter 中都会暴露出来,增加了使用的成本
- 由于继承了 src 类,所以它可以重写父类方法,使 Adapter 的灵活性增强了
对象适配器模式
实现原理
基本的思路和类的适配器模式相同,只是将 Adapter 类做修改,使用聚合关系替代继承关系
代码实现
沿用前面的代码,新建一个适配器,只是将原来的 Adapter 继承 src 类换为聚合的关系
public class VoltageAdapter2 implements Voltage5V { private Voltage220V voltage220V; public VoltageAdapter2(){ this.voltage220V = new Voltage220V(); } @Override public int output5V() { int src = this.voltage220V.output220V(); int dst = src / 44; return dst; } }
测试方法
@Test public void test02(){ System.out.println("====对象适配器模式===="); Phone.charging(new VoltageAdapter2(new Voltage220V())); }
运行结果
====对象适配器模式==== 电源输出220V 转换为5V 接收电压为5V,正常充电
接口适配器模式
接口适配器模式也可称为缺省适配器模式,当不需要实现接口的全部方法时,可先设计一个抽象类实现接口,并为该接口的每个方法都提供一个默认实现,那么该抽象类的子类就可以有选择的覆盖父类的某些方法来实现需求。
适用于一个接口不想使用其所有的方法的情况
代码实现
写一个接口,里面定义一些方法
public interface InterfaceMethod { void m1(); void m2(); void m3(); void m4(); }
一个抽象类,实现该接口
public abstract class AbstractAdapter implements InterfaceMethod { @Override public void m1() { } @Override public void m2() { } @Override public void m3() { } @Override public void m4() { } }
测试方法
@Test public void test(){ //使用匿名内部类的方式 AbstractAdapter adapter = new AbstractAdapter() { @Override public void m1() { System.out.println("我要用m1方法"); } }; adapter.m1(); }
运行结果
我要用m1方法
总结
-
三种命名方式是根据 src 是以怎样的形式给到 Adapter (在Adapter里的形式)来命名的。
-
类适配器:以类给到,在 Adapter 里,就是将 src 当做类,继承
-
对象适配器:以对象给到,在 Adapter 里, 将 src 作为一个对象,持有
-
接口适配器:以接口给到,在 Adapter 里,将 src 作为一个接口,实现
-
-
Adapter模式最大的作用还是将原本不兼容的接口融合在一起工作。