适配器模式
适配器模式是把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
1.1类的适配器模式
类的适配器模式把被适配的类的API转换为目标类的API,其静态结构图下:
类的适配器模式由目标角色、源角色、适配器角色组成。
目标(Target)角色:客户端所期待的接口。
源(Adaptee)角色:现有需要适配的类。
适配器(Adapter)角色:把源接口转换成目标接口,这里适配器角色必须是具体类。
目标角色:
/** * 目标角色 */ public interface Target { /** * 源也有的方法 */ void operate1(); /** * 源没有的方法 */ void operate2(); }
源角色:
/** * 源角色 */ public class Adaptee { public void operate1(){ System.out.println("源角色的方法 ..."); } }
适配器角色:
/** * 适配器角色 */ public class Adapter extends Adaptee implements Target{ /** * 源角色是没有这个方法的,所以需要适配器类补充这个方法 */ @Override public void operate2() { System.out.println("适配器适配源没有的方法 ..."); } }
客户端:
/** * 客户端 */ public class Client { public static void main(String[] args) { Target target = new Adapter(); target.operate1(); target.operate2(); } }
客户端希望会用Target接口,但此时我们只有一个Adaptee,且Adaptee所实现的功能就是Target所需要的功能。
类的适配器模式就是通过创建一个适配器类,并继承源对象和实现目标对象接口。使客户端所期待的Target与现有的类Adaptee关联起来。
1.2对象的适配器模式
类的适配器模式通过继承将目标角色与源角色连接起来。对象的适配器模式则通过委派来关联目标角色和源角色。结构如下:
目标角色:
/** * 目标角色 */ public interface Target { /** * 源也有的方法 */ void operate1(); /** * 源没有的方法 */ void operate2(); }
源角色:
/** * 源角色 */ public class Adaptee { public void operate1(){ System.out.println("源角色的方法 ..."); } }
适配器角色:
/** * 适配器角色 */ public class Adapter implements Target { /** * 源角色 */ private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } /** * 源角色有的方法,直接委派给源角色调用 */ @Override public void operate1() { adaptee.operate1(); } /** * 源角色是没有这个方法的,所以需要适配器类补充这个方法 */ @Override public void operate2() { System.out.println("适配器适配源没有的方法 ..."); } }
客户端:
/** * 客户端 */ public class Client { public static void main(String[] args) { Target target = new Adapter(new Adaptee()); target.operate1(); target.operate2(); } }
对象的的适配器模式可以把源类及其子类进行适配。同时,由于对象适配器模式是使用委派关联目标角色与源角色,所以目标角色的方法名可以与源角色的方法名不一致,即当目标角色的方法签名改动时,源角色无需修改,只需要更改适配器角色的方法名即可。而类的适配器模式则需要派生出一个源角色的子类对象,并在内部进行新方法的处理。然后是适配器再去适配这个派生类,麻烦很多。
1.3缺省适配器模式
缺省适配器模式为一个接口提供缺省实现,使子类从这个缺省实现进行扩展而不从原有接口扩展。
目标角色:
/** * 目标角色 */ public interface Target { void operate1(); void operate2(); }
缺省适配器:
/** * 缺省适配器 */ public abstract class DefaultAdapter implements Target { @Override public void operate1() { } @Override public void operate2() { } }
适配器1:
/** * 适配器角色1 */ public class AdapterOne extends DefaultAdapter { @Override public void operate1() { System.out.println("adapter one ..."); } }
适配器2:
/** * 适配器角色2 */ public class AdapterTwo extends DefaultAdapter{ @Override public void operate2() { System.out.println("adapter two ..."); } }
客户端:
/** * 客户端 */ public class Client { public static void main(String[] args) { Target target1 = new AdapterOne(); Target target2 = new AdapterTwo(); target1.operate1(); target1.operate2(); target2.operate1(); target2.operate2(); } }
缺省适配器缺省的其实是目标角色接口。假设目标角色接口有很多的方法,当我们实现这个接口时,必须要实现所有的接口方法,但是这些接口方法我可能只会用到其中的一两个。所以需要一个默认的类去实现这个接口的所有方法,这个任务就交给了缺省适配器类。然后我们在根据这个缺省适配器类去派生出子类,然后选择性的重写方法。
缺省适配器类必须是抽象类,因为这个类不能被实例化。
参考:
《Java与模式》