zoukankan      html  css  js  c++  java
  • Java读源代码学设计模式:适配器Adapter

    适配器模式相关源代码:slf4j-1.6.1、hibernate-3.6.7


    大家都知道。log4j是一个广泛使用的日志工具,除此之外。sun公司在JDK中也有自己的日志工具,也就是java.util.logging.Logger。

    当然还有其它一些日志工具。

    多种日志工具功能和使用方式相似,一般都包括debug、info、warn、error等日志级别的方法,但却没有实现共同的接口。这一点不像JDBC。尽管关系型数据库种类非常多。比如MySQL、Oracle等,可是有一套统一的接口,也就是JDBC。


    当然。假设你自己写一个项目,仅仅要随便找一个日志工具用即可。可是,一些开源框架的作者就比較纠结了。他不知道你的系统用的是哪种日志工具。就不知道他在开源框架中使用哪一个日志工具。

    slf4j提供了一个共同的接口。并实现了不同日志工具的适配器。所以开源框架中日志仅仅须要调用slf4j提供的接口即可,不须要关心究竟是用的哪个实现类。比如ORM框架Hibernate的日志就依赖slf4j。

    和slf4j相似的还有commons-logging等。


    源代码(因为源代码巨长,所下面面省略无关代码):

    slf4j提供统一的接口org.slf4j.Logger,该接口提供给client(如Hibernate)去调用:

    package org.slf4j;
    
    public interface Logger {
    
      public boolean isTraceEnabled();
    
      public void trace(String msg);
    
      public void trace(String format, Object arg);
    
      public void trace(String format, Object arg1, Object arg2);
    
      public void trace(String format, Object[] argArray);
    
      public void trace(String msg, Throwable t);
    
      public boolean isDebugEnabled();
    
      public void debug(String msg);
    
      public void debug(String format, Object arg);
    
      public void debug(String format, Object arg1, Object arg2);
    
      public void debug(String format, Object[] argArray);
    
      public void debug(String msg, Throwable t);
    
      public boolean isInfoEnabled();
    
      public void info(String msg);
    
      public void info(String format, Object arg);
    
      public void info(String format, Object arg1, Object arg2);
    
      public void info(String format, Object[] argArray);
    
      public void info(String msg, Throwable t);
    
      public boolean isWarnEnabled();
    
      public void warn(String msg);
    
      public void warn(String format, Object arg);
    
      public void warn(String format, Object[] argArray);
    
      public void warn(String format, Object arg1, Object arg2);
    
      public void warn(String msg, Throwable t);
    
      public boolean isErrorEnabled();
    
      public void error(String msg);
    
      public void error(String format, Object arg);
    
      public void error(String format, Object arg1, Object arg2);
    
      public void error(String format, Object[] argArray);
    
      public void error(String msg, Throwable t);
    
    }

    在clienthibernate中不是直接调用log4j或JDK logger。而是使用org.slf4j.Logger接口。任取hibernate中有日志的一段代码:

    (注:LoggerFactory.getLogger怎样实现本文不须要关注)

    package org.hibernate.impl;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {
    
    	private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);
    
    	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    		log.trace("deserializing");
    		in.defaultReadObject();
    		log.debug("deserialized: " + uuid);
    	}
    
    	private void writeObject(ObjectOutputStream out) throws IOException {
    		log.debug("serializing: " + uuid);
    		out.defaultWriteObject();
    		log.trace("serialized");
    	}
    
    }

    而log4j以及JDK的logger并没有实现slf4j的org.slf4j.Logger接口,所以slf4j要提供适配器来实现org.slf4j.Logger接口。由适配器去调用log4j或JDK的logger去实现日志,从而实现日志工具兼容。(注意:源代码中能够看出LocationAwareLogger接口继承org.slf4j.Logger所以实现LocationAwareLogger相当于实现了org.slf4j.Logger)

    Log4j适配器org.slf4j.impl.Log4jLoggerAdapter:

    package org.slf4j.impl;
    
    import java.io.Serializable;
    
    import org.apache.log4j.Level;
    import org.slf4j.Logger;
    import org.slf4j.Marker;
    import org.slf4j.helpers.FormattingTuple;
    import org.slf4j.helpers.MessageFormatter;
    import org.slf4j.spi.LocationAwareLogger;
    
    public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements
        LocationAwareLogger, Serializable {
    
      final transient org.apache.log4j.Logger logger;
    
      public boolean isDebugEnabled() {
        return logger.isDebugEnabled();
      }
    
      public void debug(String msg) {
        logger.log(FQCN, Level.DEBUG, msg, null);
      }
    
      public void debug(String format, Object arg) {
        if (logger.isDebugEnabled()) {
          FormattingTuple ft = MessageFormatter.format(format, arg);
          logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String format, Object arg1, Object arg2) {
        if (logger.isDebugEnabled()) {
          FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
          logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String format, Object[] argArray) {
        if (logger.isDebugEnabled()) {
          FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
          logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String msg, Throwable t) {
        logger.log(FQCN, Level.DEBUG, msg, t);
      }
    
    }

    Jdk logger适配器org.slf4j.impl.JDK14LoggerAdapter:

    package org.slf4j.impl;
    
    import java.util.logging.Level;
    
    import org.slf4j.Marker;
    import org.slf4j.helpers.FormattingTuple;
    import org.slf4j.helpers.MarkerIgnoringBase;
    import org.slf4j.helpers.MessageFormatter;
    import org.slf4j.spi.LocationAwareLogger;
    
    public final class JDK14LoggerAdapter extends MarkerIgnoringBase implements
        LocationAwareLogger {
    
      final java.util.logging.Logger logger;
    
      public boolean isDebugEnabled() {
        return logger.isLoggable(Level.FINE);
      }
    
      public void debug(String msg) {
        if (logger.isLoggable(Level.FINE)) {
          log(SELF, Level.FINE, msg, null);
        }
      }
    
      public void debug(String format, Object arg) {
        if (logger.isLoggable(Level.FINE)) {
          FormattingTuple ft = MessageFormatter.format(format, arg);
          log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String format, Object arg1, Object arg2) {
        if (logger.isLoggable(Level.FINE)) {
          FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);
          log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String format, Object[] argArray) {
        if (logger.isLoggable(Level.FINE)) {
          FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
          log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
        }
      }
    
      public void debug(String msg, Throwable t) {
        if (logger.isLoggable(Level.FINE)) {
          log(SELF, Level.FINE, msg, t);
        }
      }
    
    }

    在适配器模式中,一般包括下面几个部分:

    Adaptee:真正实现功能的实现类,可是与client不兼容。也就是上面代码中的java.util.logging.Logger、org.apache.log4j.Logger。


    Target:给client调用的接口,适配器实现这个接口。就是上面代码中的org.slf4j.Logger。

    Adapter:适配器,适配器实现Target接口,详细功能调用Adaptee来实现。就是上面的org.slf4j.impl.Log4jLoggerAdapter、org.slf4j.impl.JDK14LoggerAdapter。

    Client:调用Target接口。

    就是上面的Hibernate。


    总结:

    有多个相似的类(比如java.util.logging.Logger、org.apache.log4j.Logger),没有统一的接口,可是client又都想要兼容。遇到这样的情况,最好的办法是重构,也就是让他们实现同一接口。可是假设重构成本太大或者根本就无法实现同一接口(比如上面的样例。log4j和JDK logger根本就不是一家的),就必须创造出统一的接口(即org.slf4j.Logger)。并为每一个类写一个适配器(即org.slf4j.impl.Log4jLoggerAdapter、org.slf4j.impl.JDK14LoggerAdapter)。让适配器来实现统一的接口,并调用详细的实现类来实现,已达到兼容的目的。


    作者:叉叉哥   转载请注明出处:http://blog.csdn.net/xiao__gui/article/details/32695647



  • 相关阅读:
    ASP.NET页面生命周期
    C#之virtual override new解析
    js之闭包、this
    C#使用定时任务框架Windows.TaskSchedule.exe安装控制台应用程序创建的Windows服务
    C# 利用 Windows服务模板 创建、安装与卸载Windows服务
    SQL代码生成器
    C#之JSON序列化与反序列化
    Vue源码学习1——Vue构造函数
    angular编写表单验证
    使用canvas编写时间轴插件
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6916363.html
Copyright © 2011-2022 走看看