zoukankan      html  css  js  c++  java
  • mybatis框架之装饰模式

    学习开源框架源码,除了储备点知识以便于与面试官互相忽略之外,我想最重要的还是去学习大神如何写代码,如何做到职责单一,如何做到可扩展等。。。

    本篇,试着总结一下mybatis在缓存模块使用到的装饰模式。

    或许一说到装饰模式就会扯到装饰模式四种角色,但我觉得这些都是扯蛋,没必需照本宣科,我觉得myabtis框架也不是完全的装饰模式,或许可以说是变异版本。

    其实,我觉得大多的设计模式无非就是面向接口编程与接口引用的组合罢了!

    下面看看mybatis框架的cache模块是如何使用装饰模式的

    1. 首先,定义了一个cache接口,具体的功能都在接口中说明了,主要是putObject 和getObject

    public interface Cache {
    
      String getId();
      void putObject(Object key, Object value);
      Object getObject(Object key);
      Object removeObject(Object key);
      void clear();
      int getSize();
      default ReadWriteLock getReadWriteLock() {
        return null;
      }
    
    }

    2. 然后,再看一下Cache的继承体系

    清一色的java类,并没有啥抽象类或者接口,这就与教科书中的装饰模式有点区别了。。。。

    3. 每一个Cache实现类都持有一个Cache引用

    看下LoggingCache类的源代码

    public class LoggingCache implements Cache {
    
      private final Log log;
      private final Cache delegate;
      protected int requests = 0;
      protected int hits = 0;
    
      public LoggingCache(Cache delegate) {
        this.delegate = delegate;
        this.log = LogFactory.getLog(getId());
      }
    
      @Override
      public String getId() {
        return delegate.getId();
      }
    
      @Override
      public int getSize() {
        return delegate.getSize();
      }
    
      @Override
      public void putObject(Object key, Object object) {
        delegate.putObject(key, object);
      }
    
      @Override
      public Object getObject(Object key) {
        requests++;
        final Object value = delegate.getObject(key);
        if (value != null) {
          hits++;
        }
        if (log.isDebugEnabled()) {
          log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
        }
        return value;
      }
    
      @Override
      public Object removeObject(Object key) {
        return delegate.removeObject(key);
      }
    
      @Override
      public void clear() {
        delegate.clear();
      }
    
      @Override
      public int hashCode() {
        return delegate.hashCode();
      }
    
      @Override
      public boolean equals(Object obj) {
        return delegate.equals(obj);
      }
    
      private double getHitRatio() {
        return (double) hits / (double) requests;
      }
    
    }

    LoggingCache类的构造器传入了一个Cache实例delegate, 再看getObject方法

    这么一看,貌似很符合装饰模式的精神内核,但是并没有照搬装饰模式的套路。而且,,,这似乎与责任链的套路也很像。。。。

    假设LoggingCache的构造器入参是FifoCache, 而FifoCache的构造器入参又是RedsiCache, 那么在调用LoggingCache#getObject方法时就会形成一条链:

    LoggingCache#getObject()-----------> FifoCache#getObject()--------------------> RedisCache#getObject() (这难道不能算责任链嘛,当然与真正的责任又有些差别),

    而且这条调用链中,LoggingCache#getObject ()进行前、后功能增强,而FifoCache#getObject()-进行了前置功能增强, 当然RedisCache#getObject()仅是查询redis库。

    mybatis框架就是这样操作的,这条调用链具体怎么组合,完全看Cache的Caller是如何去构造链节点的关系,使用得相当灵活,我觉得它相当于: 责任链+装饰。

    而实现这种套路的技术就是Cache的所有实现类中都持有了一个Cache对象的引用。 注意是Cache对象,而非Cache的具体实现对象! 

    或许这就是面向接口编程吧!

    在以后工作中,能用就尽可能用吧,切记!

  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/z-qinfeng/p/11925078.html
Copyright © 2011-2022 走看看