1、适配器模式简介
我们常常在开发过程中遇到各个系统之间的对接问题,然而每个系统的数据模式或多或少存在区别,因此可能存在改变现有对象模型的情况,这将影响到系统的稳定。如果想在不改变原有代码结构(类的结构)的情况下完成友好对接,就需要用到适配器模式(Adapter Pattern)。
适配器模式通过定一一个适配器类作为两个不兼容的接口之间的桥梁,将一个类的接口转换成用户期望的另一个接口,使得两个或多个原本不兼容的接口可以基于适配器类一起工作。
适配器模式主要通过适配器类实现各个接口之间的兼容,该类通过依赖注入或者继承实现各个接口的功能并对外统一提供服务。
在适配器模式的实现中有三种角色:Source、Targetable、Adapter。Source是待适配的类,Targetable是目标接口,Adapter是适配器。我们在具体应用中通过Adapter将Source的功能扩展到Targetable,以实现接口的兼容。
适配器的主要实现分为三类:类适配器模式、对象适配器模式、接口适配器模式。
2、适配器模式实现
2.1 类适配器模式
在需要不改变(或者由于项目原因无法改变)原有接口或类结构的情况下扩展类的功能以适配不同的接口时,可以使用类的适配器模式。适配器模式通过创建一个继承原有类(需要扩展的类)并实现新街口的适配器类来实现。
(1)定义Source类
public class Source {
public void exitTextFile(){
System.out.println("a text file editing");
}
}
以上代码定义了待适配的Source类,在该类中实现了一个编辑文本文件的方法exitTextFile
。
(2)定义了Targetable类
public interface Targetable {
void editTextFile();
void editWordFile();
}
以上代码定义了一个Targetable
接口,在该接口中定义了两个方法:editTextFile
和editWordFile
,其中editTextFile
是Source中待适配的方法。
(3)定义Adapter继承Source类并实现Targetable接口
public class Adapter extends Source implements Targetable {
@Override
public void editTextFile() {
super.exitTextFile();
}
@Override
public void editWordFile() {
System.out.println("a word file editing");
}
public static void main(String[] args) {
Targetable target=new Adapter();
target.editTextFile();
target.editWordFile();
}
}
以上代码定义了一个Adapter类并继承了Source类实现Targetable接口,以完成对Source类的适配。适配后的类既可以编辑文本文件,也可以编辑Word文件。
在使用适配器时只需定义一个实现了Targetable接口的Adapter类并调用target中适配好的方法即可。从运行结果可以看出,我们的适配器不但实现了编辑Word文件的功能,还实现了编辑文本文件的功能,具体的执行结果如下:
2.2 对象适配器模式
对象适配器模式的思路和类适配器模式基本相同,只是修改了Adapter类。Adapter不再继承Source类,而是持有Source类的实例,已解决兼容性问题。
(1)定义适配器
public class ObjectAdapter implements Targetable {
private Source source;
public ObjectAdapter(Source source) {
super();
this.source = source;
}
@Override
public void editTextFile() {
this.source.exitTextFile();
}
@Override
public void editWordFile() {
System.out.println("a word file editing");
}
}
以上代码定义了一个名为ObjectAdapter的适配器,该适配器实现了Targetable接口并持有Source实例,在适配editTextFile()
的方法时调用Source实例提供的方法即可。
(2)使用对象适配器模式:
//使用对象适配器模式
public static void main(String[] args) {
Source source = new Source();
Targetable target = new ObjectAdapter(source);
target.editWordFile();
target.editTextFile();
}
在使用对象适配器时首选需要定义一个Source实例,然后在初始化ObjectAdapter时将Source实例作为构造函数的参数传递进去,这样就实现了对象的适配。执行结果如下:
2.3 接口适配器模式
在不希望实现一个接口中所有的方法时,可以创建一个抽象类AbstarctAdapter实现所有方法,在使用时继承该抽象类按需实现方法即可。
(1)定义公共接口Sourceable。
public interface Sourceable {
void editTextFile();
void editWordFile();
}
以上代码定义了Sourceable接口,并在接口总定义了两个方法:editTextFile()
和editWordFile
。
(2)定义抽象类AbstractAdapter并实现公共接口的方法:
public abstract class AbstarctAdapter implements Sourceable {
@Override
public void editTextFile() {
}
@Override
public void editWordFile() {
}
}
以上代码定义了Sourceable的抽象实现类AbstractAdapter,该类对Sourceable进行了重写,但是不做具体实现。
(3)定义SourceSub1类按需实现editTextFile():
public class SourceSub1 extends AbstarctAdapter {
@Override
public void editTextFile() {
System.out.println("a text file editing");
}
}
以上代码定义了SourceSub1类并继承了AbstractAdapter,由于继承父类的子类可以按需实现自己关心的方法,因此适配器来更加灵活,这里SourceSub1类实现了editTextFile
.
(4)定义SourceSub2类按需实现editWordFile()
:
public class SourceSub2 extends AbstarctAdapter {
@Override
public void editWordFile() {
System.out.println("a word file editing");
}
}
以上代码定义了SourceSub2类,继承了AbstractAdapter并实现了editWordFile
。
(5)使用接口适配器:
//使用接口适配器
public static void main(String[] args) {
SourceSub1 source1 = new SourceSub1();
SourceSub2 source2 = new SourceSub2();
source1.editTextFile();
source2.editWordFile();
}
在使用接口适配器时按需实例化不同的子类并调用实现好的方法即可。以上代码的运行结果如下: