一、适配器模式(结构型模式)
1.定义
适配器模式(Adapter Pattern)是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。(适配器模式有两种实现方式类适配器和对象适配器)
2.适配器模式角色
**(1).目标(Target)接口:**当前系统业务所期待的接口,它可以是抽象类或接口。(客户端希望的接口)
**(2).适配者(Adaptee)类:**它是被访问和适配的现存组件库中的组件接口。(真正访问的接口)
**(3).适配器(Adapter)类:**它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。(将真正访问的接口转换成客户端希望的接口)
3.代码实现方式
(1).类适配器
(1-1).创建一个目标接口,也就是客户端所期望的接口,定义需要实现的方法。
(1-2).创建适配者(这个适配者一般是原有业务中已经存在的),里面有原来的业务方法。
(1-3).创建适配器实现或者继承适配者,实现目标接口,重写目标接口中的方法,这里的方法中要调用适配者中的super.xxx()方法,然后你要再加一些逻辑啥的自己加吧。
(2).对象适配器
(2-1).创建一个目标接口,也就是客户端所期望的接口,定义需要实现的方法。
(2-2).创建适配者(这个适配者一般是原有业务中已经存在的),里面有原来的业务方法。到这里和上面没什么区别
(2-3).创建适配器实现目标接口,这里组合依赖原来的适配者作为成员变量,一般通过构造注入吧,重写目标接口的方法,这里目标方法中要调用适配者的方法,然后你要加一些逻辑就自己加吧。(对象适配器和类适配器区别在于对象的是组合依赖,类的是通过继承,前者用的多吧,解耦好点)
4.代码实现
(1).类适配器
package com.tw.designPattern.adapter.classAdapter;
/**
* 目标接口(客户端希望访问的接口)
*/
public interface Target {
void request();
}
package com.tw.designPattern.adapter.classAdapter;
/**
* 适配者(真正访问的接口/类)
*/
public class Adaptee {
public void specificRequest(){
System.out.println("适配者中的代码被调用!");
}
}
package com.tw.designPattern.adapter.classAdapter;
/**
* 类适配器
*/
public class ClassAdapter extends Adaptee implements Target{
@Override
public void request() {
super.specificRequest();
}
}
package com.tw.designPattern.adapter.classAdapter;
public class ClassAdapterTest {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
测试结果
适配者中的代码被调用!
(2).对象适配器
(2-1).场景
模拟新能源汽车的发动机。 新能源汽车的发动机有电能发动机(ElectricMotor)和光能发动机(OpticalMotor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。
客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor, 然后再定义电能适配器(ElectricAdapter)和光能适配器(OpticalAdapter)去适配这两种发动机。
(2-2).具体代码
package com.tw.designPattern.adapter.objectAdapter;
/**
*
* 目标(Target):发动机
*
*/
public interface Motor {
void drive();
}
package com.tw.designPattern.adapter.objectAdapter;
/**
* 适配者(Adaptee)电能发动机
*/
public class ElectricMotor {
public void electricDrive(){
System.out.println("电能发动机驱动汽车!");
}
}
package com.tw.designPattern.adapter.objectAdapter;
/**
* 适配者(Adaptee)光能发动机
*/
public class OpticalMotor {
public void opticalDrive(){
System.out.println("光能发动机驱动汽车!");
}
}
package com.tw.designPattern.adapter.objectAdapter;
/**
* 适配器(Adapter)电能适配器
*/
public class ElectricAdapter implements Motor{
private ElectricMotor electricMotor;
public ElectricAdapter(){
electricMotor = new ElectricMotor();
}
@Override
public void drive() {
electricMotor.electricDrive();
}
}
package com.tw.designPattern.adapter.objectAdapter;
/**
* 适配器(Adapter)光能适配器
*/
public class OpticalAdapter implements Motor{
private OpticalMotor opticalMotor;
public OpticalAdapter(){
opticalMotor = new OpticalMotor();
}
@Override
public void drive() {
opticalMotor.opticalDrive();
}
}
package com.tw.designPattern.adapter.objectAdapter;
public class MotorAdapterTest {
public static void main(String[] args) {
Motor electricAdapter = new ElectricAdapter();
electricAdapter.drive();
Motor opticalAdapter = new OpticalAdapter();
opticalAdapter.drive();
}
}
测试结果
电能发动机驱动汽车!
光能发动机驱动汽车!
(2-3).双向适配器
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
/**
* 目标接口(Target)
*/
public interface TwoWayTarget {
void request();
}
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
/**
* 目标实现(Target)
*/
public class TargetRealize implements TwoWayTarget{
@Override
public void request() {
System.out.println("目标代码被调用!");
}
}
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
/**
* 目标适配者(Adaptee)
*/
public interface TwoWayAdaptee {
void specificRequest();
}
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
/**
* 适配者实现(Adaptee)
*/
public class AdapteeRealize implements TwoWayAdaptee{
@Override
public void specificRequest() {
System.out.println("适配者代码被调用!");
}
}
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
/**
* 双向适配器(Adapter)
*/
public class TwoWayAdapter implements TwoWayTarget,TwoWayAdaptee{
private TwoWayTarget target;
private TwoWayAdaptee adaptee;
public TwoWayAdapter(TwoWayTarget target){
this.target = target;
}
public TwoWayAdapter(TwoWayAdaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
@Override
public void specificRequest() {
target.request();
}
}
package com.tw.designPattern.adapter.objectAdapter.twoWayAdapter;
public class TwoWayAdapterTest {
public static void main(String[] args) {
TwoWayAdaptee adaptee = new AdapteeRealize();
TwoWayAdapter twoWayTarget = new TwoWayAdapter(adaptee);
System.out.println("目标通过双向适配器访问适配者!");
twoWayTarget.request();
TwoWayTarget target = new TargetRealize();
TwoWayAdapter twoWayAdaptee = new TwoWayAdapter(target);
System.out.println("适配者通过双向适配器访问目标!");
twoWayAdaptee.specificRequest();
}
}
测试结果
目标通过双向适配器访问适配者!
适配者代码被调用!
适配者通过双向适配器访问目标!
目标代码被调用!
双向适配器个人理解啊
这里定义目标接口(TwoWayTarget)和适配者接口(TwoWayAdaptee),一是为了面向接口开发(依赖倒置原则),二了Java是单继承、多实现的。然后了目标实现(TargetRealize)就是单纯的实现目标接口重写方法,方法里写上自己的业务么,适配者实现(AdapteeRealize)同样的在子类中写上自己的业务,然后双向适配器(TwoWayAdapter)实现目标接口(TwoWayTarget)和适配者接口(TwoWayAdaptee),提供两个构造方法分别注入目标和适配者,然后再分别重写目标接口(TwoWayTarget)的方法,在具体实现中调用适配者的方法,同样重写适配者接口(TwoWayAdaptee)的方法,在具体实现中调用目标的方法,这个就是把类适配结构和对象适配器结构融合在一起了。不够解耦,我觉有实际需要的话可以用的,总比都用对象适配器那样在多谢一个适配器类吧。耦合就耦合吧。
5.优缺点
(1).优点
(1-1). 客户端通过适配器可以透明地调用目标接口。
(1-2).复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
(1-3).将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
(1-4).在很多业务场景中符合开闭原则。
注:以上优点啊基本上都是对象适配器的,一般开发过程中基本上不会用继承的方式的,除非是那种特定场景啊。
(2).缺点
(2-1).在写适配器过程中,你要考虑全应用场景,费脑子,然后加了适配器的话,代码复杂度会高那么一点,不利于维护。
6.应用场景
(1).以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
(2).使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。
说一下在我实际开发中了解的适配器模式啊,springboot中的HandleAdapter,这个看名字就知道了,还有就是HttpServlet也是适配器。有兴趣可以去看下源码。
注:内容参考网络上各种资料,还有一些本人的理解和思想,仅为了学习记录和分享一下自己所学之处,如有不足的地方麻烦大牛指出,如有侵权的地方,请联系删除,谢谢