java-设计模式(结构型)-【适配器模式】
1.适配器(Adapter Mode)
定义:将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adapter(适配器)两个身份
目的是消除由于接口不匹配所造成的类的兼容性问题。
我们经常碰到需要将两个没有关系的类组合在一起使用,第一种方法是,修改各自的接口,但是违背了开闭原则
第二种方法是,使用Adapter,在两种接口之间创建一个混合接口(混血儿)。
分类:类的适配器模式、对象的适配器模式、接口的适配器模式
三个角色:
- 目标角色(Traget:interface):期待得到的接口
- 源(Adapee)角色:现在需要适配的接口
- 适配器(Adapter:class)角色:必须是具体类
1.1 类的适配器模式:继承的方式适配
1.1.1 图解
1.1.2 三个角色
//待适配的源 public class Source { //方法一: public void method1() { System.out.println("source:method1方法"); } } //需要实现的接口 interface Targetable { void method1(); //方法二 void method2(); } //以类继承的方式进行适配 class Adapter extends Source implements Targetable { //继承了方法一 //重写方法二: @Override public void method2() { // TODO Auto-generated method stub System.out.println("Targetable:method2方法"); } }
1.1.3 测试
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub //使用Target接口里定义的方法,不需要"Adapter ad" Targetable ad=new Adapter(); System.out.println("adapter-----"); ad.method1(); ad.method2(); Targetable wp=new Wrapper(new Source()); System.out.println("wrapper-----"); wp.method1(); wp.method2(); } }
1.1.4 运行结果
adapter----- source:method1方法 Targetable:method2方法 wrapper----- source:method1方法 Targetable:method2方法
1.2 对象适配器:组合的方式适配
1.2.1 图解
1.2.2 代码
public class Source { public void method1() { System.out.println("source:method1方法"); } } interface Targetable { void method1(); void method2(); } class Wrapper implements Targetable { //组合的方式适配 private Source s=null; public Wrapper(Source s) { this.s=s; } @Override public void method1() { // TODO Auto-generated method stub s.method1(); } @Override public void method2() { // TODO Auto-generated method stub System.out.println("Targetable:method2方法"); } }
1.3 两者方式的对比
- 类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
- 对象适配器:一个适配器可以把多种不同的源(以多态形式:将子类传入)适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。
- 因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。
- 类适配器:由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,
- 当适配器继承了Adaptee后,就不可能再去处理 Adaptee的子类了。
- 类适配器:适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。
- 对象适配器:要重定义Adaptee的行为比较困难,这种情况下,可以通过定义Adaptee的子类来实现重定义,然后让适配器组合子类。
- 虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。
建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。
1.4 接口适配器:对接口的部分方法用抽象类抽出来实现使用
1.4.1 代码
//接口:待适配中 interface Targetable { void method1(); void method2(); } //抽象类:中间层,让子接口无需实现父接口的所有未实现方法,有选择的实现自己要实现的方法 abstract class Wrapper2 implements Targetable { public void method1(){} public void method2(){} } //只实现方法1 class SourceSub1 extends Wrapper2 { public void method1() { System.out.println("SourceSub1:method1"); } } //只实现方法2 class SourceSub2 extends Wrapper2 { public void method2() { System.out.println("SourceSub2:method2"); } }
1.4.2 测试
public class Test { public static void main(String[] args) { // TODO Auto-generated method stub //使用Target接口里定义的方法,不需要"Adapter ad" Targetable s1=new SourceSub1(); Targetable s2=new SourceSub2(); //S1:只实现方法1 s1.method1(); s1.method2(); //S2:只实现方法2 s2.method1(); s2.method2(); } }
1.4.3 运行结果
SourceSub1:method1 SourceSub2:method2
1.5 适配器的优点
- 更好的复用性
系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
- 更好的扩展性
在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。