装饰者模式( Decorator Pattern),在不改变原有对象的基础上,将功能附加到原有对象上。比继承更有弹性。装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
装饰者模式者存在两个重要的角色: 装饰者和被装饰者
搞清楚这一点,下面还是通过代码来展示装饰者的实现流程:
① 创建装饰者的总接口
public interface IPacketCreator {
String handleContent();//用于内容处理
}
在装饰者设计模式当中,装饰者和被装饰者拥有相同的超类
② 创建被装饰者
public class PacketBodyCreator implements IPacketCreator {
@Override
public String handleContent() {
return "Content of packet";
}
}
- 此类是被装饰者的角色,是具体的组件,它的功能是构造要发布信息的核心内容但是它不负责将其构造成一个格式工整,可直接发布的数据格式。是整个过程当中的核心组件
③ 创建装饰者
添加html类容装饰器。处理html相关格式
public class PacketBodyDecorator implements IPacketCreator {
IPacketCreator componet ;
public PacketBodyDecorator(IPacketCreator iPacketCreator) {
componet = iPacketCreator;
}
@Override
public String handleContent() {
System.out.println("添加HTML装饰");
StringBuffer sb = new StringBuffer();
sb.append("<html>");
sb.append("<body>");
sb.append(componet.handleContent());
sb.append("</body>");
sb.append("</html>");
return sb.toString();
}
}
添加请求头装饰者
public class PacketHeaderDecorator implements IPacketCreator {
IPacketCreator componet ;
public PacketHeaderDecorator(IPacketCreator iPacketCreator) {
componet = iPacketCreator ;
}
@Override
public String handleContent() {
System.out.println("添加请求头装饰");
StringBuffer sb = new StringBuffer();
sb.append("Cache-Control:no-cache\n");
sb.append("DATE:2020-7-1 18:12:55\n");
sb.append(componet.handleContent());
return sb.toString();
}
}
来测试一下:
IPacketCreator ipc = new PacketHeaderDecorator(new PacketBodyDecorator(new PacketBodyCreator()));
System.out.println(ipc.handleContent());
输出结果:
添加请求头装饰
添加HTML装饰
Cache-Control:no-cache
DATE:2018-2-1 18:12:55
<html><body>Content of packet</body></html>
调用链路如下:
以上就简单的实现了一下装饰者的工作流程。
装饰者模式最典型的应用是Java源码中的IO操作相关的OutputStream和InputStream类族了。
先看一下输出流OutputStream中装饰者设计模式的使用:
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("D://decorator.txt")));
//dos1去掉了缓存装饰者。不添加缓冲功能
//DataOutputStream dos1 = new DataOutputStream(new FileOutputStream("D://decorator.txt"));
long begins = System.currentTimeMillis();
for (int i=0 ; i<10000 ; i++ ) {
dos.writeBytes(String.valueOf(i));
}
System.out.println("Spend "+(System.currentTimeMillis()-begins)+" millis");
dos.flush();
dos.close();
类的结构图如下:
这个例子中:
角色 | 实现类 |
---|---|
装饰者接口超类 | OutputStream |
被装饰者 | FileOutputStream |
装饰者 | BufferedOutputStream DataOutputStream |