该模式在java中比较典型的应用也就是jdk的io系统了
装饰模式类图
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauI3b0FmcvNWZk9CX5AzLclDMwIzLcNHZh9GbwV3LcRnblRnbvNWLwd3Lc12bj5yb1dWat5WZoNnL3d3dvw1LcpDc0RHaiojIsJye.jpg)
好吧,其实这类图只对UML熟悉的人才有用,装饰模式有啥用?说白了就是在原来类的功能上,对这些功能做一些增强处理,当然为了增强功能而通过继承也是一种有效的方式,当然对于各种组合比较多的情况下,使用继承可能会有太多的类出现,所以就需要使用装饰模式,当然装饰模式的缺点也是显而易见的,使用上会比较麻烦。
举个例子:
FileReader
StringReader
我要为这两个类的read功能增加缓存功能,如果使用继承方式,我需要两个子类来完成,也许这两个子类得叫BufferedFileReader和BufferedFileStringReader,如果要增加缓存功能的类有十个,那么子类也就需要十个,但是如果用装饰模式,我只要增加一个装饰类既可满足,BufferedReader类,这个就是jdk1.1的io系统设计。
普通的装饰模式简单示例
//总接口
public interface Compoent {
public Object needGirl();
}
//执行类
public class GirlGet implements Compoent {
public Object needGirl() {
// TODO Auto-generated method stub
System.out.println("给你个素颜的女优美眉");
return null;
}
}
//装饰类父类,可有可无
public abstract class Decorator implements Compoent {
public abstract Object needGirl();
}
//装饰类
public class MakeUpDecorator {
private Compoent c = null;
public MakeUpDecorator(Compoent _c) {
this.c = _c;
}
public Object needGirl() {
// 女孩化妆
girlMarkUp();
return c.needGirl();
}
public void girlMarkUp() {
// 化妆
System.out.println("素颜的女优不好,化妆下!");
}
}
//客户端
public class Client {
public static void main(String[] ben){
MakeUpDecorator mud = new MakeUpDecorator(new GirlGet());
mud.needGirl();
}
}
套用io模式的BufferedReader,StringReader,Reader的read功能来做说明:
首先来说明这三个类在上述类图的位置:
Reader:Compoent也是Decorator的基础类
StringReader:ConcreateComponent
BufferedReader:ConcreateDecoratorA
写出简略代码,从jdk1.1中的源码抠出来,去除了很多与该模式无关的代码:
//Reader
public abstract class Reader implements Readable, Closeable {
abstract public int read(char cbuf[], int off, int len) throws IOException;
}
//StringReader
public class StringReader extends Reader {
public int read(char cbuf[], int off, int len) throws IOException {
int n = Math.min(length - next, len);
str.getChars(next, next + n, cbuf, off);
next += n;
return n;
}
}
//BufferedReader
public class BufferedReader extends Reader{
private Reader in = null;
cb = new char[sz];
public BufferedReader(Reader reader)[
in = reader;
}
public int read(char cbuf[], int off, int len) throws IOException
int n = read1(cbuf, off, len);
if (n <= 0)return n;
while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n);
if (n1 <= 0)break;
n += n1;
}
return n;
}
private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {
//当读取的长度超过缓存长度的时候,直接从in里面读取,也就失去了这个装饰类的作用了。
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
//如果读取的下个字符索引超过了当前的缓存长度,也就是说不在缓存中,那么重新加载下一组缓存.
fill();
}
//当加载缓存后发现,读取的下个字符索引仍旧超过缓存长度,其实就是加载下一组失败,也就是说已经读取完毕了。
if (nextChar >= nChars)return -1;
int n = Math.min(len, nChars - nextChar);
//从缓存中读取字符
System.arraycopy(cb, nextChar, cbuf, off, n);
nextChar += n;
return n;
}
private void fill() throws IOException {
//创建一个缓存,缓存的长度可设置,为设置是默认的
//首先从in中获取指定长度的流到缓存中去。加速访问.
//核心语句就下面一句
n = in.read(cb, dst, cb.length - dst);
}
}
从上面可以看出,BufferedReader类其实就是将Reader的子类(ConcreateComponent)也就是这里的StingReader的数据放入缓存,然后操作read方法的时候,从缓存中读取,但是实际上的流还是通过StringReader来获取的。也就是说BufferedReader对StringReader类的read功能增加了缓存功能,在事实上,你不使用BufferedReader也可以直接操作StringReader的read功能,只是没有了缓存效果而已。
客户端使用的代码:
String s = "This is the/n/ninternal StringReader buffer./ndderwe";
StringReader stringReader = new StringReader(s);
BufferedReader bufReader = new BufferedReader(stringReader);
可以看到,客户端使用是比较麻烦的,这就是装饰模式的缺点。