mybatis原理与设计模式-日志模块- 适配器模式

 在讲设计模式之前,得先知道java程序设计中得六大原则,才能更好得理解我们得系统为什么需要设计模式

1 单一职责原则

  一个类只负责一种职责,只有这种职责的改变会导致这个类的变更。绕口一点的正统说法:不要存在多于一个原因导致类变更

  假如:类T 负责有两种职责 P1,P2;当P1发生改变时,需要修改类T,这时候可能会对P2造成影响。

  所以不要为了图代码量少,二将不同职责放入到一个类里面。

2 里氏替换原则

  只要父类出现的地方,都可以用子类替换,并且不会对程序造成影响,在实现上来说就是子类不要覆盖父类的非抽象方法,但可以重载。

  重载时需要注意,入参的要求要比父类宽松(保证可以进入),返回要比父类更加严格(保证出去不会有问题),这也正是实现里氏替换的基础。

3 依赖倒置原则

  高层模块不应该依赖低层模块,二者都应该依赖其抽象,翻译一下就是面向接口编程;接口一般是行为的集合,也就是尽可能的对行为抽象。

  抽象不应该依赖细节,细节应该依赖抽象。

4 接口隔离原则

  翻译一下就是接口的功能尽可能单一,接口本质上是两个类之间关系的纽带,关系中不需要有的,在接口中不应该体现。如:A 通过接口I依赖B,假如接口I中有A 不需要的方法,那么这个接口就是不合理的,B必须要实现这个不需要的方法,徒劳无功。

5 迪米特法则(最少知道原则)

  也就是说一个对象要对其他对象保持尽可能少的了解,即低耦合性,低耦合可以最大限度的保证代码的可复用性。这个实际上是针对被依赖的类来说的,对于被依赖的类,尽可能的将复杂的逻辑封装起来,对外只提供public方法,外部不需要知道内部的逻辑。

6 开闭原则

  尽量通过扩展来面对需求的更改或者系统的变化,尽量不要对原有内容修改。

在这六大原则中,开闭原则应该是最基础得原则

适配器模式

在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。在实际开发中,对象适配器的使用频率更高

在对象适配器模式结构图中包含如下几个角色:

Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。

Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。

Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码

MyBatis的日志功能源码包logging就是适配器模式的应用,主要是为了将市场的各种日志插件,转换为MyBatis的日志接口,统一使用,下面是日志包的包结构

 其中我们可以重点关注下LogFactory这个工厂类

package org.apache.ibatis.logging;

import java.lang.reflect.Constructor;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public final class LogFactory {

  /**
   * Marker to be used by logging implementations that support markers
   */
  public static final String MARKER = "MYBATIS";

  private static Constructor<? extends Log> logConstructor;

  static {
    tryImplementation(new Runnable() {
      public void run() {
        useSlf4jLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useCommonsLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useLog4J2Logging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useLog4JLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useJdkLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useNoLogging();
      }
    });
  }

  private LogFactory() {
    // disable construction
  }

  public static Log getLog(Class<?> aClass) {
    return getLog(aClass.getName());
  }

  public static Log getLog(String logger) {
    try {
      return logConstructor.newInstance(new Object[] { logger });
    } catch (Throwable t) {
      throw new LogException("Error creating logger for logger " + logger + ".  Cause: " + t, t);
    }
  }

  public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
    setImplementation(clazz);
  }

  public static synchronized void useSlf4jLogging() {
    setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
  }

  public static synchronized void useCommonsLogging() {
    setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);
  }

  public static synchronized void useLog4JLogging() {
    setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
  }

  public static synchronized void useLog4J2Logging() {
    setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
  }

  public static synchronized void useJdkLogging() {
    setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class);
  }

  public static synchronized void useStdOutLogging() {
    setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);
  }

  public static synchronized void useNoLogging() {
    setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);
  }

  private static void tryImplementation(Runnable runnable) {
    if (logConstructor == null) {
      try {
        runnable.run();
      } catch (Throwable t) {
        // ignore
      }
    }
  }

 

}

在LogFactory类加载的时候会执行静态代码块,其逻辑是按序加载并实例化对应的日志组件的适配器,然后使用Logfactory.logConstructor这个静态字段,记录当前使用的的第三方日志组件的适配器

tryImplementation(new Runnable() {
      public void run() {
        useLog4JLogging();
      }
    });

private static void tryImplementation(Runnable runnable) {
if (logConstructor == null) {
try {
runnable.run();
} catch (Throwable t) {
// ignore
}
}
}
 
 
 private static void setImplementation(Class<? extends Log> implClass) {
    try {
    //获取指定适配器的构造方法 Constructor<? extends Log> candidate = implClass.getConstructor(new Class[] { String.class }); Log log = candidate.newInstance(new Object[] { LogFactory.class.getName() }); log.debug("Logging initialized using '" + implClass + "' adapter."); logConstructor = candidate; } catch (Throwable t) { throw new LogException("Error setting Log implementation. Cause: " + t, t); } }
 
这个方法首先会检查logConstructor这个是不是空,如果为空则调用runnable.run方法,(注意不是start方法)


接下来我们一起看一个其中的适配器类
 
 
import org.apache.ibatis.logging.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.spi.LocationAwareLogger;

public
class Slf4jImpl implements Log { private Log log; public Slf4jImpl(String clazz) { Logger logger = LoggerFactory.getLogger(clazz); if (logger instanceof LocationAwareLogger) { try { // check for slf4j >= 1.6 method signature logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class); log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger); return; } catch (SecurityException e) { // fail-back to Slf4jLoggerImpl } catch (NoSuchMethodException e) { // fail-back to Slf4jLoggerImpl } } // Logger is not LocationAwareLogger or slf4j version < 1.6 log = new Slf4jLoggerImpl(logger); } public boolean isDebugEnabled() { return log.isDebugEnabled(); } public boolean isTraceEnabled() { return log.isTraceEnabled(); } public void error(String s, Throwable e) { log.error(s, e); } public void error(String s) { log.error(s); } public void debug(String s) { log.debug(s); } public void trace(String s) { log.trace(s); } public void warn(String s) { log.warn(s); } }
Slf4jImpl实现了Log接口
并在类中使用组合的方式引入Log的引入

结合上面的适配模式可以分析,Slf4jImpl就是Apdater类,Log接口就是Target
LoggerFactory.getLogger(clazz)这个操作就是获取  org.slf4j.Logger 他就是Adaptee类
这里只分析其中一个实现类,感兴趣的可以去看其它的实现类,基本一致所以这里就不做讲解了

  没有英汉互译结果
   请尝试网页搜索

猜你喜欢

转载自www.cnblogs.com/clovejava/p/9610707.html
今日推荐