- 适配器模式
把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够工作。
1. 类的适配器模式
- 目标角色:期望的接口,对于类的适配器模式,此角色不可以是具体类。
- 源角色:需要适配的接口。
- 适配器角色:把源接口转换成目标接口,此角色必须是具体类。
public interface Target { void fun2(); }
public class Adaptee { public void fun1(){ } }
// 适配器Adapter扩展了Adaptee,同时也实现了接口Target。这样Adapter的类型是Adaptee同时也提供Target要求的方法。 public class Adapter extends Adaptee implements Target { @Override public void fun2() { // TODO Auto-generated method stub } }
2. 对象的适配器模式
- 目标角色:期望的接口,可以是具体或抽象的类。
- 源角色: 需要适配的接口。
- 适配器角色:把源接口转换成目标接口,此角色必须是具体类。
public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } public void fun1(){ adaptee.fun1(); } @Override public void fun2() { // TODO Auto-generated method stub } }
可以看出,对象适配器与类适配器的区别是使用对象组合代替了类型继承。这样一个适配器可以把多种不同的源适配器到同一个目标。但与类适配器相比,要想置换源类的方法就不太容易,如果一定要置换,可以先做好一个源类的子类置换掉方法,然后将子类当作真正的源进行适配。不过要是想增加一些新的方法则很方便,而且新增加的方法可以同时适用于所有的源。
- 装饰器模式
装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。
- 抽象构建角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构建角色:定义一个将要接收附加责任的类。
- 装饰角色:持有一个构建对象的实例,并定义一个与抽象构建接口一致的接口。
- 具体装饰角色:负责给构建对象贴上附加的责任。
具体装饰角色实现了构建接口,对于每一个实现的方法都委派给父类的构建角色,关键在于它功能的增强,而不是单纯地委派。
- 示例:IO设计
java api的io类库中对于适配器装饰器的应用随处可见,这里以读取文件为例,看一下其中的相关的几个类。
// 读取一个文件内容 BufferedReader in = new BufferedReader(new FileReader(new File("test.txt")));
BufferedReader是一个典型的装饰器模式,它实现了Reader接口,同时也拥有Reader子类的一个实例,这里也就是FileReader,然后将所有的读取任务都委托给了FileReader的实例,但是增加了缓存读取功能。
我们通常会说InputStreamReader是从byte输入流到char输入流的一个适配器,但其实起到适配器作用的是StreamDecoder,它拥有InputStream的实例同时实现了Reader接口,而InputStreamReader在此基础上进一步装饰了StreamDecoder。
说一个让java初学者纠结的一个问题,io流关闭问题:由于使用的装饰器模式,对于io流的close,我们只要调用最外层的close方法就可以了。比如BufferedReader会将close的操作委托给reader实例,这个实例正常是InputStreamReader的实现,然后InputStreamReader又委托给StreamDecoder,最后StreamDecoder又会委托给InputStream的实现类,最终实现了IO流关闭,反过来如果提前调用了委托类的close方法,那么上层的读取也会失败。
#笔记内容参考《java与模式》