设计模式详解(七)——适配器模式
类适配器模式是通过让Adapter(适配器)实现Target(被适配者)的抽象接口,然后继承Adaptee(要适配者),具体适配过程是由我们的适配器的Resuest()方法中对Adaptee(要适配者)的SpecificRequest()方法进行适配,使得适配器的Request()方法返回我们需要的被适配者,供我们使用。适配器模式的用意是要改变源的接口,以便于目标接口相容。根据适配器类与适配者类的
适配器模式简介
适配器模式定义
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。简单的说就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。
适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
在业务开发中我们会经常的需要做不同接口的兼容,比如需要把各个业务线的各种类型服务做统一包装,再对外提供接口进行使用。而这在我们平常的开发中也是非常常见的。
根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
适配器模式包含以下角色:
目标抽象类:Target,该角色把其他类转换为我们期望的接口,可以是一个抽象类或接口,也可以是具体类。定义Client使用的与特定领域相关的接口
被适配者: Adaptee ,原有的接口,也是希望被适配的接口。定义一个已经存在的接口,这个接口需要适配,需要适配别人(要适配者)
适配器: Adapter, 将被适配者和目标抽象类组合到一起的类。对Adaptee的接口与Target接口进行适配
适配器模式优缺点:
优点:
1、将目标类和适配者类解耦
2、增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性
3、灵活性和扩展性都非常好,符合开闭原则
缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。
2、 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景
(1)系统需要使用现有的类,而此类的接口不符合需要。
(2)需要一个统一的输出接口,而输入类型不可预知。
(3)创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(协同工作。
适配器模式的实现
适配器模式有两种:“对象”适配器和“类”适配器。
对象适配器模式: 基本思路与类适配器模式相同, 只是将 Adapter适配器类修改, 不是继承 Adaptee被适配者, 而是拥有 Adaptee类的实例, 以解决兼容性的问题。
类适配器模式: Adapter适配器类, 继承 Adaptee被适配器类, 实现 Target目标类的接口, 完成适配。类适配器模式是通过让Adapter(适配器)实现Target(被适配者)的抽象接口,然后继承Adaptee(要适配者),具体适配过程是由我们的适配器的Resuest()方法中对Adaptee(要适配者)的SpecificRequest()方法进行适配,使得适配器的Request()方法返回我们需要的被适配者,供我们使用。
以下举一个类适配器的例子:
如:在生活中手机充电器, 需要将家用220V的交流电 转换为 5V的直流电后, 才能对手机充电
手机充电器 相当于 Adapter适配器
220V的交流电 相当于 Adaptee 被适配者
5V的直流电 相当于 Target目标
Adaptee被适配器类: 220V电压
/**
* @author yyx
*/
public class Adaptee {
public int output220V() {
System.out.println("正常220V电压");
return 220;
}
}
Target目标接口: 输出5V电压
/**
* @author yyx
*/
public interface Target {
public int output5V();
}
Adapter适配器类: 将220V电压转换成 5V电压
/**
* @author yyx
*/
public class Adapter extends Adaptee implements Target {
@Override
public int output5V() {
// 获取到220V的电压
int a = output220V();
// 处理电压,转成5V
int b = a / 44;
return b;
}
}
手机实体类
/**
* @author yyx
*/
public class Phone {
public void charging(Adapter voltage) {
if (voltage.output5V() == 5) {
System.out.println("电压适配为5V,可以充电");
} else if (voltage.output5V() > 5) {
System.out.println("电压大于5V,不能充电~");
}
}
}
测试Client:
/**
* @author yyx
*/
public class Client {
public static void main(String[] args) {
System.out.println("类适配器模式");
Phone phone = new Phone();
phone.charging(new Adapter());
}
}
运行结果如下所示:
类适配器模式
正常220V电压
电压适配为5V,可以充电
注意:
Java是单继承机制, Adapter类适配器需要继承 Adptee被适配者类, 导致 Target目标必须是接口, 有一定的局限性 (继承, 破坏了类的封装性, 父类对于子类来说是透明的, 且耦合度高)
由于继承 Adptee被适配者类, 所以可以根据需求重写 Adptee被适配者类的方法, 是的Adapter的灵活性增强了
** 对象适配器的例子:**
对象适配器模式: 基本思路与类适配器模式相同, 只是将 Adapter适配器类修改, 不是继承 Adaptee被适配者, 而是拥有 Adaptee类的实例, 以解决兼容性的问题.
修改Adapter适配器类, 将继承Adaptee类, 修改成拥有Adaptee类的成员属性
Adapter适配器类
/**
* @author yyx
*/
//public class Adapter extends Adaptee implements Target {
// @Override
// public int output5V() {
// // 获取到220V的电压
// int a = output220V();
// // 处理电压,转成5V
// int b = a / 44;
// return b;
// }
//}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter() {
}
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public int output5V() {
int dst = 0;
if (adaptee != null) {
int src = adaptee.output220V();
System.out.println("使用对象适配器进行适配");
dst = src / 44;
System.out.println("适配完成,输出电压为:" + dst);
}
return dst;
}
}
测试Client:
/**
* @author yyx
*/
public class Client {
// public static void main(String[] args) {
// System.out.println("类适配器模式");
// Phone phone = new Phone();
// phone.charging(new Adapter());
// }
public static void main(String[] args) {
System.out.println("对象适配器模式");
Phone phone = new Phone();
phone.charging(new Adapter(new Adaptee()));
}
}
运行结果如下所示:
对象适配器模式
正常220V电压
使用对象适配器进行适配
适配完成,输出电压为:5
电压适配为5V,可以充电
注意:对象适配器模式相比于类适配器模式会更加灵活一些,我们的Adaptee是通过构造器传入的,这样可以更方便我们代码的扩展(多态),而且类适配器如果Target不是一个接口,也是一个类的话,Java中是不支持多继承的。
总而言之:
适配器模式的用意是要改变源的接口,以便于目标接口相容。缺省适配的用意稍有不同,它是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。建议尽量使用对象的适配器模式,多用合成/聚合、少用继承。
总结:
1.从用户的角度看不到被适配者,是解耦的
2.用户直接调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
3.适配器实现了用户收到反馈结果,感觉只是和目标接口交互
4.适配器将一个对象包装起来用以改变其接口。
5.当需要使用一个现有的类而其接口并不符合你的需求时,可以使用适配器。
6.实现一个适配器可能会花一番功夫,可能也会毫不费力,原因是有其目标接口的大小与复杂度决定。
以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)