在java 的IO体系中,除了常用到的装饰模式外,还有一个常用的设计模式:适配器设计模式,主要用来实现字节流和字符流类的适配转换工作。相比装饰模式而言,适配器模式就相对简单多了,完成一个适配器模式需要三个组件:目标接口(也就是最终要调用的对象的类型)Target,需要被适配的类(也就是真正需要调用能力拥有者的类)Adaptee,适配器者Adapter(就是把Adaptee的能力填充到Target接口里面的类,Adapter一般继承于或实现Target),文字说明有点复杂,举个例子就明白了
Target:
Public class Target{
Public void fun(){};
}
Adaptee:
Public class Adaptee {
Public void realFun(){System.out.println(“itis real fun”);}
}
Adapter:
Public class Adapte extends Target{
Adaptee adaptee = new Adaptee();
Public void fun(){
Adaptee. realFun();
}
}
--上面就是整个适配器模式实现的例子了,客户端使用时:
Target target = new Adapter ();
Target. fun();
执行结果:it is real fun
就是这么简单,说白了就是组合模式,任何设计模式中出现某个类使用其他类的能力,不管怎么吹,什么设计模式高大上名词一大堆,归根结底离不开继承和组合两种模式。而继承比较明显简单,所以很多设计模式就是变着花样使用组合模式。组合与多态的花样结合制造出了很多的“设计模式”。
说完适配器模式原理后,看看字符流是如何通过这个模式使用字节流的能力的,首先确定角色:字符流的子类Target,字节流子类Adaptee,适配器OutputStreamWriter InputStreamReader,具体是怎么实现的能,举个write能力的例子
字符流:
public abstract class Writer{
abstract public void write(char cbuf[], intoff, int len);
}
适配器:
public class OutputStreamWriter extendsWriter {
private final StreamEncoder se;
public void write(char cbuf[], int off, intlen) throws IOException {
se.write(cbuf, off, len);
}
}
和简单经典的适配器例子的区别在于StreamEncoder并不是直接的字节流子类,而是更深一层的适配器:
public class sun.nio.cs.StreamEncoder{
OutputStream out;
public void write(char cbuf[], int off, intlen)
{
最终调用了
out.write();
}
}
简单点理解,StreamEncoder包含了字节流对象,拥有了字节流的能力。所以当在客户端如此调用时:
Write wr = new OutputStreamWriter();
Wr.write();
实际上是调用了StreamEncoder中包含的字节流对象OutputStream out的write能力,当然要进行一层编码转换的包装以适应字符流的写特性。