装饰者模式的应用场景
装饰者模式(Decorator Pattern)是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰者模式在我们生活中应用也比较多如给煎饼加鸡蛋;给蛋糕加上一些水果;给房子装修等,为对象扩展一些额外的职责。装饰者在代码程序中适用于以下场景:
1、用于扩展一个类的功能或给一个类添加附加职责。
2、动态的给一个对象添加功能,这些功能可以再动态的撤销
我记得有做蛋糕的小游戏,先会有一个面饼,然后可以加奶油、巧克力、水果等,我们以此举例:
蛋糕创建者接口
public interface Creator {
//这里用字符串描述蛋糕的外观
public String createCake();
}
蛋糕生产者CakeCreator
public class CakeCreator implements Creator {
public String createCake(){
String msg="制作了一个圆形蛋糕";
// System.out.println(msg);
return msg;
}
}
专门加奶油的生产者
public class CreamAddCreator implements Creator {
Creator creator ;
public CreamAddCreator(Creator creator) {
this.creator=creator;
}
@Override
public String createCake() {
return creator.createCake()+"+一份奶油";
}
}
专门加水果的生产者
public class FruitAddCreator implements Creator {
Creator creator ;
public FruitAddCreator(Creator creator) {
this.creator=creator;
}
@Override
public String createCake() {
return creator.createCake()+"+一份水果";
}
}
测试类:
public class DecoratorTest {
public static void main(String[] args) {
Creator creator = new CakeCreator();
System.out.println(creator.createCake());
creator = new FruitAddCreator(creator);
System.out.println(creator.createCake());
creator = new CreamAddCreator(creator);
System.out.println(creator.createCake());
}
}
执行结果:
这个例子中我们通过组合不同的装饰者就可以实现各种样式蛋糕的制作。而不用变更最初CakeCreator 中的逻辑。这个过程和动态代理有点类似,不同的是更加灵活。如果用静态代理完成加水果和奶油的蛋糕,很容易实现。但是如果逻辑变为 先加奶油再加水果,甚至加3分水果两份奶油,那静态代理实现起来就比较复杂了。而我们的装饰者模式可以随意组合实现。
装饰者模式和适配器模式对比
装饰者和适配器模式都是包装模式(Wrapper Pattern),装饰者也是一种特殊的代理模式
装饰者模式在源码中的应用
装饰器模式在源码中也应用得非常多,在JDK 中体现最明显的类就是IO 相关的类,如BufferedReader、InputStream、OutputStream,看一下常用的InputStream 的类结
在Spring 中的TransactionAwareCacheDecorator 类我们也可以来尝试理解一下,这个类主要是用来处理事务缓存的
public class TransactionAwareCacheDecorator implements Cache {
private final Cache targetCache;
public TransactionAwareCacheDecorator(Cache targetCache) {
Assert.notNull(targetCache, "Target Cache must not be null");
this.targetCache = targetCache;
}
public Cache getTargetCache() {
return this.targetCache;
}
...
}
TransactionAwareCacheDecorator 就是对Cache 的一个包装。再来看一个MVC 中的装饰者模式HttpHeadResponseDecorator 类
public class HttpHeadResponseDecorator extends ServerHttpResponseDecorator {
public HttpHeadResponseDecorator(ServerHttpResponse delegate) {
super(delegate);
}
...
}
最后,看看MyBatis 中的一段处理缓存的设计org.apache.ibatis.cache.Cache 类,
从名字上来看其实更容易理解了。比如FifoCache 先入先出算法的缓存;LruCache 最近最少使用的缓存;TransactionlCache 事务相关的缓存,都是采用装饰者模式
装饰者模式的优缺点
优点:
1、装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
3、装饰者完全遵守开闭原则。
缺点:
1、会出现更多的代码,更多的类,增加程序复杂性。
2、动态装饰时,多层装饰时会更复杂。