0x01:适配器模式简介
对于适配器置信不会生疏,生存中的例子亘古未有,像耳机转接线,充电器适配器,水管适配接口等等。通过类比很容易了解软件中的适配器模式。
客户端须要一个target(指标)接口,然而不能间接重用曾经存在的adaptee(适配者)类,因为它的接口和target接口不统一,所以须要adapter(适配器)将adaptee转换为target接口。前提是target接口和已存在的适配者adaptee类所做的事件是雷同或类似,只是接口不同且都不易批改。如果在设计之初,最好不要思考这种设计模式。凡事都有例外,就是设计新零碎的时候思考应用第三方组件,因为没必要为了投合第三方组件批改本人的软件设计格调,能够尝试应用适配器模式。
上面是一个十分典型的应用适配器模式的场景:
Sun公司在1996年公开了Java语言的数据库连贯工具JDBC,JDBC使得Java语言程序可能与数据库连贯,并应用SQL语言来查问和操作数据。JDBC给出一个客户端通用的形象接口,每一个具体数据库厂商(如SQL Server、Oracle、MySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。形象的JDBC接口和各个数据库引擎API之间都须要相应的适配器软件,这就是为各个不同数据库引擎筹备的驱动程序。
另外一个比拟典型的适配器场景J2EE标准与J2EE标准实现的服务器。SUN公司提供了一套J2EE标准,而后不同厂商依据本人的了解实现了不同的应用服务器。SUN公司提供了一套servlet api标准,而后实现这套标准的驰名应用服务器有Apache Tomcat、Jetty、Oracle 的 Weblogic、IBM 的 WebSphere 等。
适配器模式的UML类图如下
从类图上看次要蕴含如下角色:
- 指标角色(target):这是客户所期待的接口。指标能够是具体的或形象的类,也能够是接口;
- 适配者角色(adaptee):已存在接口(能够了解是第三方提供的接口),然而和客户端期待的接口不兼容;
- 适配器角色(adapter):将已有接口转换成指标接口(能够了解我方须要的接口);
0x02:适配器模式的实现
类适配器模式(class adapter pattern)
通过继承进行适配(类间继承)。类适配器模式在编译时实现target(指标)接口。这种适配器模式应用了多个实现了期待的接口或者曾经存在的接口的多态接口。比拟典型的就是:target接口被创立为一个纯正的接口,Java不反对多继承的语言。
Target:Target指标角色,该角色定义把其余类转换为何种接口,也就是冀望接口,通常状况下是一个接口或一个抽象类,个别不会是实现类
public interface Target { public void request();}
Adaptee:Adaptee源角色,想把谁转换为指标角色,这个“谁”就是源角色,它是曾经存在的、运行良好的类或对象
public class Adaptee { public void specificRequest() { System.out.println("我是曾经存在的运行良好的第三方厂商"); }}
Adapter:Adapter适配器角色,是适配器模式的外围角色,它的职责是通过继承或是类关联的形式把源角色转换为指标角色
public class Adapter extends Adaptee implements Target { @Override public void request() { super.specificRequest(); }}
ConcreteTarget:指标角色的实现类
public class ConcreteTarget implements Target { @Override public void request() { System.out.println("没有减少适配器的我方一般实现逻辑"); }}
类适配器模式测试代码
public class Client { public static void main(String[] args) { //原有无适配器的业务逻辑 Target target = new ConcreteTarget(); target.request(); //减少适配器后的业务逻辑 Target target2 = new Adapter(); target2.request(); }}
对象适配器模式(object adapter pattern)
通过对象档次的关联关系进行委托(对象的合成关系/关联关系)。对象适配器模式在运行时实现target(指标)接口。在这种适配器模式中,适配器包装了一个类实例。在这种状况下,适配器调用包装对象实例的办法。
Target:客户所期待的接口。指标能够是具体的或形象的类,也能够是接口
public class Target { public void request() { System.out.println("没有适配器的一般申请"); }}
Adaptee:须要适配的类
public class Adaptee { public void specificRequest() { System.out.println("适配器类实现的非凡申请"); }}
Adapter:通过在外部包装一个Adaptee对象,把源接口转换成指标接口
public class Adapter extends Target { private Adaptee adaptee = new Adaptee(); @Override public void request() { //替换原理的逻辑,调用适配类的逻辑 adaptee.specificRequest(); }}
对象适配器模式测试代码
public class Client { public static void main(String[] args) { Target target = new Adapter(); target.request(); }}
缺省适配器模式(default adapter pattern),也叫默认适配器模式、接口适配器模式
当不须要全副实现接口提供的办法时,能够设计一个适配器抽象类实现接口,并为接口中的每个办法提供默认办法实现或者空实现(如果大家做过GUI编程,就能够常常遇到这种实现,特地是各种控件的事件监听都提供了适配器类),抽象类的子类就能够有抉择的笼罩父类的某些办法实现需求,它实用于一个接口不想应用所有的办法的状况。在java8后,接口中能够有default办法,就不须要这种缺省适配器模式了。接口中办法都设置为default,实现为空,这样同样同样能够达到缺省适配器模式同样的成果。
target:蕴含了很多没有实现的操作接口
public interface Target { public abstract void operation1(); public abstract void operation2(); public abstract void operation3();}
Adapter:默认实现了所有操作抽象类,只是所有的实现都是空实现
public abstract class DefaultAdapter implements Target{ @Override public void operation1() { } @Override public void operation2() { } @Override public void operation3() { }}
测试缺省适配器模式须要用到的类(相当于GUI编程的一个组件,比方按钮Button)
public class Operator { private Target target; public void addOperation(Target target) { this.target= target; } public void operation1() { target.operation1(); } public void operation2() { target.operation2(); } public void operation3() { target.operation3(); }}
缺省适配器模式测试代码
public class Client{ public static void main(String[] args) { // 原来要实现所有操作类的操作 Operator operator1= new Operator(); operator1.addOperation(new Target() { @Override public void operation1() {} @Override public void operation2() { System.out.println("invoke operation2"); } @Override public void operation3() {} }); operator1.operation2(); // 2、应用缺省适配器只须要实现须要用到的接口办法 Operator operator2 = new Operator(); operator2.addOperation(new DefaultAdapter() { @Override public void operation2() { System.out.println("invoke operation2"); } }); operator2.operation2(); }}
适配器模式实质上是现有的不兼容的接口转换为须要的接口。类适配器模式以继承现有类的形式转换;对象适配器模式以聚合对象实例的形式转换;接口适配器模式以实现接口的形式转换。适配器模式是在现有的类和零碎都不易批改的状况下才应用,在零碎设计之初慎用该设计模式。