设计模式——装饰者模式

一、定义与简单实现

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;
  }

补充:装饰者模式中装饰者对象必须依赖原对象,可用工厂模式或者建造者模式封装整个创建过程。

posted on 2020-04-02 16:05  FFStayF  阅读(405)  评论(0编辑  收藏  举报