装饰者模式有一个设计非常巧妙的结构,可以为对象动态添加功能。在基本的设计原则中,有一个重要的原则叫做合成/聚合复用原则。根据该原则的思想,代码复用应该尽可能使用委托,而不是继承。
因为继承是一种紧密耦合,任何父类的改动都会影响其子类,不利于系统维护。而委托则是松散耦合,只要接口不变,委托类的变动并不会影响其上层维护对象。
装饰者模式充分运用了这种思想,通过委托机制,复用系统的各个组件,在运行时,将这些组件功能进行叠加,从而构造出一个“超级对象”,使其拥有所有这些组件的功能。
而各个子功能模块,被很好的维护在各个组件的相关类中,拥有简洁的系统结构。
下面以一个例子来说明。
IPacketCretor即装饰者接口,用于处理具体的内容。PacketBodyCreator是具体的组件,用于构造要发布的信息的核心内容,但是它不负责将其构造成一个格式工整、可直接发布的数据格式。
PacketHTTPHeaderCreator负责给具体的内容加上HTTP头部,PacketHTMLHeaderCreator负责将给定的内容格式化成HTML文本。3个功能组件相互独立且分离,便于系统维护。
IPacketCreator
/**
* Created by j.tommy on 2017/9/14.
*/
public interface IPacketCreator {
public String handleContent(); // 用于处理具体内容
}
PacketBodyCreator
/**
* Created by j.tommy on 2017/9/14.
*/
public class PacketBodyCreator implements IPacketCreator {
@Override
public String handleContent() {
return "Content of packet.";
}
}
PacketDecorator
/**
* Created by j.tommy on 2017/9/14.
*/
public abstract class PacketDecorator implements IPacketCreator {
IPacketCreator ipc;
public PacketDecorator(IPacketCreator ipc) {
this.ipc = ipc;
}
}
PacketHTMLHeaderCreator
/**
* Created by j.tommy on 2017/9/14.
*/
public class PacketHTMLHeaderCreator extends PacketDecorator {
public PacketHTMLHeaderCreator(IPacketCreator ipc) {
super(ipc);
}
@Override
public String handleContent() {
StringBuffer buffer = new StringBuffer();
buffer.append("<html>");
buffer.append("<body>");
buffer.append(ipc.handleContent());
buffer.append("</body>");
buffer.append("</html>");
return buffer.toString();
}
}
PacketHTTPHeaderCreator
/**
* Created by j.tommy on 2017/9/14.
*/
public class PacketHTTPHeaderCreator extends PacketDecorator {
public PacketHTTPHeaderCreator(IPacketCreator ipc) {
super(ipc);
}
@Override
public String handleContent() {
StringBuffer buffer = new StringBuffer();
buffer.append("Cache-Control:no-cache\n");
buffer.append(ipc.handleContent());
return buffer.toString();
}
}
测试类Main
/**
* Created by j.tommy on 2017/9/14.
*/
public class Main {
public static void main(String[] args) {
IPacketCreator ipc = new PacketHTTPHeaderCreator(new PacketHTMLHeaderCreator(new PacketBodyCreator()));
System.out.println(ipc.handleContent());
}
}
输出:
对于装饰者模式,另一个值得关注的地方是它的使用方法。在本例中,通过层层构造和组装装饰者与被装饰者到一个对象中,使其有机的结合在一起工作。
在本例中,共生成3个对象实例,PacketBodyCreator作为核心组件被首先 构造,其次是PacketHTMLHeaderCreator(将内容包装成HTML格式),最后是PacketHTTPHeaderCreator(添加HTTP头)。
在JDK的实现中,也有装饰者模式的实现。一个典型的例子就是OutputStream和InputStream的实现。以OutputStream为例,OutputStream提供的功能较弱,通过各种装饰器的增强,OutputStream可以被赋予强大的功能。
生成一个有缓冲功能的流对象
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("d:/test.txt")));
生成一个没有缓冲功能的流对象
DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/test.txt"));
第1种加入了性能组件BufferedOutputStream,第二种则没有。因此第1种拥有更好的性能。
在BufferedOutputStream中,并不是每次调用write方法都会向磁盘写入数据,而是将数据写入缓冲,只有缓冲满的时候才会调用FileOutputStream的write方法向磁盘写入,以此实现功能组件与性能组件的完美分离。
参考:《《Java程序性能优化-让你的Java程序更快、更稳定》(葛一宁等编著)》