适配器模式
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配的而无法在一起工作的两个类能够在一起工作 –《Java与模式》
适配器模式的意义
一个经典的例子是:假如说目前有一批电器所需要的电压是220V,但是出现了一个只需要110V电压的电器,但是我们需要是使用这个110V电压的电器,那么这个时候在无法改变电器的情况下,我们只能对电压进行降幅,使用变压器对原有的电压转化为110V,此刻我们就可以使用该电器了,那么这种变压的行为我们称之为适配器模式
适配器模式分类
类的适配器模式和对象的适配器模式
- 类的适配器模式
简单分析一下这里涉及到的角色
- Target(目标对象):可以理解为上述例子中的所有电器的一个所需要电压规范定义
- ConcreteTarget(具体目标对象):具体某一个需要多少电压的电器(这里我暂定为220V电压的电器,这里符合上述例子)
- Adapter(适配器类):这个可以理解为一个变压器
- Adaptee(具有特殊功能的类):可以理解为一个110V电压的电器
- Client(客户端):这里我们只是做一个测试类
具体代码
public interface Target { void request(); } public class ConcreteTarget implements Target{ @Override public void request() { System.out.println("我是需要220V电压的电器"); } } public class Adaptee { public void specialRequest() { System.out.println("我是需要110V电压的电器"); } } public class Adapter extends Adaptee implements Target { @Override public void request() { System.out.println("我是变压器,我已经把电压转化为110V了"); super.specialRequest(); } } public class Client { public static void main(String[] args) { Target target1 = new ConcreteTarget(); target1.request(); Target target2 = new Adapter(); target2.request(); } }
- 对象适配器模式
这里分析的角色的关系和与之前的类的绝大数相同,唯一不同的是在Adapter和Adaptee两者的关系,在类适配器模式是两个是作为继承的模式存在的;在对象适配器模式中是引用的关系存在,作为Adaptee作为一个Adapter的成员变量而存在的
具体代码
public class ConcreteTarget implements Target{ @Override public void request() { System.out.println("我是需要220V电压的电器"); } } public class Adaptee { public void specialRequest() { System.out.println("我是需要110V电压的电器"); } } public class Adapter implements Target{ private Adaptee adaptee; public Adapter(Adaptee adaptee) { super(); this.adaptee = adaptee; } @Override public void request() { System.out.println("我是变压器,我已经把电压转化为110V了"); adaptee.specialRequest(); } } public class Client { public static void main(String[] args) { Target target1 = new ConcreteTarget(); target1.request(); Target target2 = new Adapter(new Adaptee()); target2.request(); } }
缺省适配模式
缺省适配(default Adapter)模式提供了一个默认的一个公共实现(也可以理解为空实现),那么接下来所有去实现这个指定规范的接口时,可以根据自己需要去重写自己需要的实现
这里我们提供一个场景出来:假如我们需要定义一个人类的接口,而作为人类来说可能掌握很多技能,不同的人掌握不同的技能,比如说开车,写代码之类的,那么作为不同工作的人,可能自己掌握的技能必然是不一样的。
代码如下
public interface Person { void drive(); void code(); } public class Coder implements Person { @Override public void drive() { // 什么也不做,空实现 } @Override public void code() { System.out.println("我可是会写代码的;(*^__^*) 嘻嘻……"); } } public class Driver implements Person { @Override public void drive() { System.out.println("我可是会开车的;(*^__^*) 嘻嘻……"); } @Override public void code() { // 什么也不做,空实现 } }
简单分析一下上面代码可能以后存在的问题,假如在未来,在我们系统中Person这个接口越来越复杂,那么每一个去实现Person接口的具体实现类,都必须要重新一遍(或者说都必须要去添加不需要的空实现),但是作为Coder来说,其实对于他来说,他只关心自己需要实现的code方法,而且其他方法对于他来说,他不关心;那么每一次去增加一个Person接口的功能,那么导致Coder类都去维护一个他本身不关心方法,这样不合适;这个时候我们可以使用缺省适配模式来解决这个问题
代码如下
public interface Person { void drive(); void code(); } public abstract class AbstractPerson implements Person { @Override public void drive() { //空实现,什么也不干 } @Override public void code() { //空实现,什么也不敢 } } public class Coder extends AbstractPerson { @Override public void code() { System.out.println("我可是会写代码的;(*^__^*) 嘻嘻……"); } } public class Driver extends AbstractPerson { @Override public void drive() { System.out.println("我可是会开车的;(*^__^*) 嘻嘻……"); } }
按照缺省适配模式进行编写时,当我们每次去修改Person接口时,我们只需要在AbstractPerson添加相应的空实现,不需要去修改具体的Coder,Driver实现类