设计模式——装饰者模式
一、定义与简单实现
1、定义
- 动态地将责任附加到对象上去,提供了比继承更有弹性的替代方案。
装饰者模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰者模式是在运行时增加行为。
通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:创建一个装饰类,组合目标类,然后动态的增强目标对象的方法,
注意:装饰类必须目标对象有相同的接口
2、UML类图
装饰者模式是个常用的模式。重点是需要有相同的接口,然后要利用组合,不要利用继承。
我理解的UML类图
官方UML类图给装饰者再加一层抽象类:这里抽象类作用是复用代码,没有这个需求时,可以不用加,后面框架中的实现,就没有加
动态地将责任附加到对象上去,若要扩展功能,装饰着提供了比继承更有弹性的替代方案。用到的设计模式原则:
- 多用组合,少用继承
- 针对接口编程
- 对扩展开发,对修改关闭
3、简单实现
前面:mybatis——缓存:redis实现分布式二级缓存
public interface Component { void methodA(); } public class ConcreteComponent implements Component { @Override public void methodA() { System.out.println("想加特技"); } } public class DecoratorComponent implements Component { private Component component; public DecoratorComponent(Component component){ this.component = component; } @Override public void methodA() { component.methodA(); System.out.println("特技得加钱"); } } public class Main { public static void main(String[] args) { Component concrete = new ConcreteComponent(); Component decorator = new DecoratorComponent(concrete); decorator.methodA(); } }
二、框架中的装饰者模式
1、JDK中输入输出流
FilterInputStream的类其实是左边InputStream类的一个装饰者类。
2、Mybatis二级缓存
mybatis源码中org.apache.ibatis.cache.decorators包下的类全是装饰类,都是对二级缓存类PerpetualCache.class功能的增强。例如
FifoCache:增强缓存置换功能,设置缓存大小,当缓存满后,先进先出(FIFO)算法置换(利用队列实现)
LruCache:增强缓存置换功能,设置缓存大小,当缓存满后,最久未使用(LRU)算法置换(利用LinkedHashMap实现)
其实这里的FifoCache、LruCache中可以加一层抽象类,因为有共同的方法getId()等
下面是二级缓存创建,Configuration.caches
/* org.apache.ibatis.builder.MapperBuilderAssistant#useNewCache */ public Cache useNewCache(Class<? extends Cache> typeClass, Class<? extends Cache> evictionClass, Long flushInterval, Integer size, boolean readWrite, boolean blocking, Properties props) { //建造器模式创建cache Cache cache = new CacheBuilder(currentNamespace) .implementation(valueOrDefault(typeClass, PerpetualCache.class)) .addDecorator(valueOrDefault(evictionClass, LruCache.class)) .clearInterval(flushInterval) .size(size) .readWrite(readWrite) .blocking(blocking) .properties(props) .build(); configuration.addCache(cache); currentCache = cache; return cache; } public Cache build() { //默认implementation = PerpetualCache.class //decorators.add(LruCache.class) setDefaultImplementations(); //利用反射创建一个PerpetualCache实例 //类似 Cache cache = new PerpeualCache(id); Cache cache = newBaseCacheInstance(implementation, id); setCacheProperties(cache); // issue #352, do not apply decorators to custom caches if (PerpetualCache.class.equals(cache.getClass())) { for (Class<? extends Cache> decorator : decorators) { //装饰者模式功能增强,注意这里是个循环,可多次增强 //默认LruCache.class //类似cache = new LruCache(cache); cache = newCacheDecoratorInstance(decorator, cache); setCacheProperties(cache); } cache = setStandardDecorators(cache); } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) { cache = new LoggingCache(cache); } return cache; }
补充:装饰者模式中装饰者对象必须依赖原对象,可用工厂模式或者建造者模式封装整个创建过程。