MyBatis框架之适配器模式

MyBatis框架有多处使用了设计模式,我们在阅读其源码时,需要好好体会它对设计模式的使用,以便于照着葫芦画瓢。本篇主要是记录一下适配器模式的使用。

适配器模式理解起来很简单,相当于使用了一个接口,将老旧的功能包装一下,使之适应新的需求(或许有错误,但错就错吧)。

MyBatis框架对适配器的使用,主要体现在Log日志这一块。

MyBatis自个定义了一个Log接口,接口嘛,规范而已。 而而且要怎么操作我不管,只需要按照我的规范来即可。

/**
 * MyBatis定义的日志接口规范
 */
public interface Log {

  boolean isDebugEnabled();

  boolean isTraceEnabled();

  void error(String s, Throwable e);

  void error(String s);

  void debug(String s);

  void trace(String s);

  void warn(String s);

}

该接口定义了Mybatis直接使用的日志方法,而Log接口具体由谁来实现呢?Mybatis提供了多种日志框架的实现,这些实现都匹配这个Log接口所定义的接口方法,最终实现了所有外部日志框架到Mybatis日志包的适配。

MyBatis框架之适配器模式

MyBatis就是这么刚,提供了如此之多实现方式。 啥意思呢,就是Log接口适配了这么多的日志框架, 我们在使用时,只需要随便引入其中一种日志框架,那么就可以使用Log接口规范去操作日志了。

下面我们来看一个具体的实现。 毕竟接口是啥事都干不了的,干事还得靠实现啦!

以log4j为例

import org.apache.ibatis.logging.Log;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

public class Log4jImpl implements Log {

  private static final String FQCN = Log4jImpl.class.getName();

  // 将log4j框架的日志实例对象定义成全局变量,以便于类中其它方法操作
  private final Logger log;
  
  /**
   * 通过构造创建真正的日志操作实例,此处是apache的log4j
   */
  public Log4jImpl(String clazz) {
    log = Logger.getLogger(clazz); // 真正干事的东西
  }

  /**
   * 调用MyBatis的Log接口方法isDebugEnabled,其实质就是调用apache log4j日志对象的isDebugEnabled方法
   * 其它方法也是一样原理
   */
  @Override
  public boolean isDebugEnabled() {
    return log.isDebugEnabled();
  }

  @Override
  public boolean isTraceEnabled() {
    return log.isTraceEnabled();
  }

  @Override
  public void error(String s, Throwable e) {
    log.log(FQCN, Level.ERROR, s, e);
  }

  @Override
  public void error(String s) {
    log.log(FQCN, Level.ERROR, s, null);
  }

  @Override
  public void debug(String s) {
    log.log(FQCN, Level.DEBUG, s, null);
  }

  @Override
  public void trace(String s) {
    log.log(FQCN, Level.TRACE, s, null);
  }

  @Override
  public void warn(String s) {
    log.log(FQCN, Level.WARN, s, null);
  }

}

再比如另一个实现适配jdk日志

import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.ibatis.logging.Log;

/**
 * @author Clinton Begin
 */
public class Jdk14LoggingImpl implements Log {

  private final Logger log;

  public Jdk14LoggingImpl(String clazz) {
    log = Logger.getLogger(clazz);  // 真正干事的东西
  }

  @Override
  public boolean isDebugEnabled() {
    return log.isLoggable(Level.FINE);
  }

  @Override
  public boolean isTraceEnabled() {
    return log.isLoggable(Level.FINER);
  }

  @Override
  public void error(String s, Throwable e) {
    log.log(Level.SEVERE, s, e);
  }

  @Override
  public void error(String s) {
    log.log(Level.SEVERE, s);
  }

  @Override
  public void debug(String s) {
    log.log(Level.FINE, s);
  }

  @Override
  public void trace(String s) {
    log.log(Level.FINER, s);
  }

  @Override
  public void warn(String s) {
    log.log(Level.WARNING, s);
  }

}

代码很简单,原理也是一样一样的。

总结:

适配器模式就是这么简单,代码套路就是先创建一个接口,接口的各种实现子类裹挟着真正干事的的对象。为啥叫适配器模式呢?估计就是通过这个接口将调用方与真正干事的实例关联起来。是不是感觉有点解耦的意味? 我觉得有那么点意思,但其实质还是将多种干事儿的实例,通过一个接口进行规范,以方便调用方的使用。 即是,调用方不必关心具体的实现。

是不是觉得有点像门面模式,其实不是哟! 

是不是觉得有点像策略模式,我觉得有那么点意味。。。。但还是有差别。