首先简单介绍一下装饰者模式是个什么样的结构?
装饰者模式的结构设计很巧妙,可以动态添加对象功能。它遵循“合成/聚合复用原则”,这个原则的思想是代码复用应该尽可能使用委托,而不是继承。因为继承是一种紧密耦合,任何父类的改动都会影响其子类,不利于系统维护。而委托则是松散耦合,只要接口不变,委托类的改动并不会影响其上层对象。
装饰者模式就是充分运用了这种思想,通过委托机制,复用系统中的各个组件,在运行时,可以将这些功能组件进行叠加,从而构造一个“超级对象”,使其拥有所有这些组件的功能。而各个子功能模块,被很好地维护在各个组件的相关类中,层级结构整洁易于维护,这样可以很好地将功能组件和核心组件进行分离,彼此互不影响,并在需要的时候,有机地结合起来。
接下来我使用案例分析一下装饰者模式
- 首先看一下装饰者模式的结构图:
从图中可以看出,装饰者(Decorator)和被装饰者(ConcreteComponent)拥有相同的接口Component。被装饰者通常是系统的核心组件,实现特定的功能目标。而装饰者则可以在被装饰者的方法前后,加上特定的前置处理和后置处理,增强被装饰者的功能。 - 装饰器接口:
/**
* @Summary 装饰者模式-Component
* @Description 声明装饰接口
* @Author helon
* @Date 2018/11/18 4:24 PM
* @Param
* @return
**/
public interface IPacketCreator {
/**
* @Summary 核心组件处理内容的抽象方法
* @Description TOD
* @Author helon
* @Date 2018/11/18 4:23 PM
* @Param []
* @return java.lang.String
**/
String handleContent();
}
- 核心组件实现类(被装饰者):
/**
* @className: PacketCoreCreator
* @summary: 装饰者模式-ConcreteComponent
* @Description: 具体的组件,它的功能是构造要处理的核心内容
* @author: helon
* date: 2018/11/18 4:30 PM
* version: v1.0
*/
public class PacketCoreCreator implements IPacketCreator {
/**
* @Summary 核心组件
* @Description 具体处理逻辑实现
* @Author helon
* @Date 2018/11/18 4:34 PM
* @Param []
* @return java.lang.String
**/
@Override
public String handleContent() {
return "deal core content\n";
}
}
- 装饰者抽象类:
/**
* @className: PacketDecorator
* @summary: 装饰者模式-装饰者Decorator
* @Description: 装饰者抽象类
* @author: helon
* date: 2018/11/18 4:39 PM
* version: v1.0
*/
public abstract class PacketDecorator implements IPacketCreator {
IPacketCreator component;
public PacketDecorator(IPacketCreator component) {
this.component = component;
}
}
- 装饰者具体实现类(用户相关操作):
/**
* @className: PacketUserDecorator
* @summary: 具体实现用户相关操作的装饰器
* @Description: TODO
* @author: helon
* date: 2018/11/18 4:45 PM
* version: v1.0
*/
public class PacketUserDecorator extends PacketDecorator {
public PacketUserDecorator(IPacketCreator c) {
super(c);
}
@Override
public String handleContent() {
StringBuilder sb = new StringBuilder();
sb.append("deal user content begin\n");
//核心组件处理逻辑
sb.append(component.handleContent());
sb.append("deal user content end\n");
return sb.toString();
}
}
- 装饰者具体实现类(日期相关操作):
/**
* @className: PacketDateDecorator
* @summary: 具体实现时间相关操作的装饰器
* @Description: TODO
* @author: helon
* date: 2018/11/18 5:00 PM
* version: v1.0
*/
public class PacketDateDecorator extends PacketDecorator {
public PacketDateDecorator(IPacketCreator c) {
super(c);
}
@Override
public String handleContent() {
StringBuilder sb = new StringBuilder();
sb.append("deal date:" + System.currentTimeMillis() + "\n");
sb.append(component.handleContent());
sb.append("deal date:" + System.currentTimeMillis() + "\n");
return sb.toString();
}
}
- 测试结果:
/**
* @className: TestMain
* @summary: main方法测试
* @Description: TODO
* @author: helon
* date: 2018/11/18 5:08 PM
* version: v1.0
*/
public class TestMain {
public static void main(String[] args) {
IPacketCreator packetCreator = new PacketDateDecorator(
new PacketUserDecorator(
new PacketCoreCreator()));
System.out.println(packetCreator.handleContent());
}
}
//执行结果:
deal date:1542532385110
deal user content begin
deal core content
deal user content end
deal date:1542532385110
Process finished with exit code 0
总结
以上就是装饰者模式的设计流程,确实是一个不错的设计模式,非常实用。其实在JDK的实现中,就有不少组件是用装饰者模式实现的,其中比较典型的例子就是OutputStream和InputStream类族的实现。比如:OutputStream类提供的方法比较简单,功能比较弱,但是通过各种装饰者的增强,OutputStream对象可以被赋予强大的功能。它的设计模式可以参考以下结构图:
其中,以OutputStream为核心的装饰者模式的实现,FileOutputStream为核心类,它实现了向文件写数据。使用DateOutputStream可以在FileOutputStream的基础上,增强对多种数据类型的写操作支持。更多的实现细节可以参考IO相关类的源码,一起学习交流,如有不正确的地方,欢迎指正批评。