适配器模式
适配器模式定义:将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容不能在一起工作的那些类可以一起工作。适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个接口的功能。这种模式涉及到一个单一的类,该类负责加入的或不兼容的接口功能。
现实中的典型适配器例子:读卡器,电源适配器....
适配器模式的实现主要分对象适配器模式和类适配器模式,类图结构示例如下:
(1)意图:
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
(2)主要解决:
主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
(3)何时使用:
1)系统需要使用现有的类,而此类的接口不符合系统的需要。
2)想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
3)通过接口转换,将一个类插入另一个类系中。
(4)如何解决:
继承或依赖(推荐)。
(5)关键代码:
适配器继承或依赖已有的对象,实现想要的目标接口。
(1)优点:
1)可以让任何两个没有关联的类一起运行。
2)提高了类的复用。
3)增加了类的透明度。
4)灵活性好。
(2)缺点:
1)过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2)由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
(3)使用场景:
有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。
(4)注意事项:
适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。
适配器模式的实现主要有对象适配器模式和类适配器模式,其中,对象适配器模式通过组合来实现;类适配器模式使用继承和实现,一般情况下,建议使用对象适配器模式实现而尽量少用类适配器实现。
(1)示例场景:
假设要实现一个电源适配器,将输出220v电压的输出适配成输出5v电源输出。
(2)代码示例如下:
原始输出类:
//原始输出
class Adaptee{
public int output220V(){
return 220;
}
}
目标输出接口:
//目标接口
interface Target{
int output5v();
}
对象适配器类,通过组合来实现:
//对象适配器,通过组合关系来实现
class Adapter implements Target{
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public int output5v() {
int i = adaptee.output220V();
//...一系列转换操作
System.out.println(String.format("原始电压:%d v -> 输出电压:%d v",i,5));
return 5;
}
}
使用测试示例:
public class ObjectAdapterTest {
public static void main(String[] args) {
//将原始的输出电压进行适配输出5v电压
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.output5v();
}
}
结果输出示例:
原始电压:220 v -> 输出电压:5 v
(1)场景同上:
假设要实现一个电源适配器,将输出220v电压的输出适配成输出5v电源输出。
(2)代码示例:
原始输出类:
//原始输出
class Adaptee2{
public int output220V(){
return 220;
}
}
目标接口类:
//目标输出接口
interface Target2{
int output5v();
}
适配器类,通过继承来实现:
//类的适配器模式:通过继承关系来实现
class Adapter2 extends Adaptee2 implements Target2{
@Override
public int output5v() {
int i = output220V();
//...一系列转换操作
System.out.println(String.format("原始电压:%d v -> 输出电压:%d v",i,5));
return 5;
}
}
测试示例:
public class ClassAdapterTest {
public static void main(String[] args) {
Adapter2 adapter2 = new Adapter2();
adapter2.output5v();
}
}
测试结果输出示例:
原始电压:220 v -> 输出电压:5 v
可以看出,对象适配器实现和类适配实现均可完成适配器功能的实现,但是类适配器使用的是继承方式实现,在实现接口方法的同时也继承了原始父类的方法。对应Adapter类而言,多了不必要的方法,这往往对Adapter类的设计目的而言是没有意义的,还会容易误解。一般情况下,推荐使用对象适配模式来吧实现适配器模式。
(1)Spring中的应用ApplicationListener(旧接口)和GenericApplicationListener(新接口)中,为了兼容新旧,它们之间的适配使用了适配器模式,使用的是对象适配器模式;(注ApplicationListener本身使用的是观察者模式)
(2)java.util包中的Arrays类的asList方法,也使用的适配器模式。该方法源码如下:
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
这里直接new一个List对象进行返回。new ArrayList()方法源码如下:
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable{
private static final long serialVersionUID = -270174811045198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
//其他方法....
}
这里通过直接将输入数组转换成一个泛型数组,从而实现了将对象转换为List对象。
本文源代码:
声明:本文部分内容整理来源于网络,仅做个人学习使用!侵删~
本文部分内容参考链接:
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- ovod.cn 版权所有 湘ICP备2023023988号-4
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务