适配器模式相关源代码: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

Java读源代码学设计模式:适配器Adapter的更多相关文章

  1. 设计模式--适配器(Adapter)模式

    今天学习另一个设计模式,适配器(Adapter)模式,这是一个共同方向,但有特殊要求,就应用到此设计模式.写到这里,想起很久以前,有写过一篇<ASP.NET的适配器设计模式(Adapter)&g ...

  2. Objective-C设计模式——适配器Adapter(接口适配)

    适配器模式 适配器模式通俗来讲,其实就是对客户端添加新的类但却不修改客户端和新的类的接口.此时我们需要自己来实现适配,在适配器模式中有Target对象,即客户端所需要的接口对象,Adaptee对象,即 ...

  3. 设计模式 适配器-Adapter

    适配器模式:将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间. 直接上图.下面是对象适配器的类图.由于Java不支持多继承.所以这是Java的适配器实现方式. 结合H ...

  4. Ruby设计模式透析之 —— 适配器(Adapter)

    转载请注明出处:http://blog.csdn.net/sinyu890807/article/details/9400153 此为Java设计模式透析的拷贝版,专门为Ruby爱好者提供的,不熟悉R ...

  5. 设计模式学习心得<适配器 Adapter>

    适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能. 这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接 ...

  6. Java学习-005-初学常用的几个经典循环控制源代码

    最近一段时间公司 App 改版,一直处在需求评审.代码评审.测试计划.测试用例.用例评审.用例执行.缺陷管理.测试总结的循环中,因而博客也好久没有更新了.虽然工作确实忙了点,但是也是自己懒惰了,从今天 ...

  7. 2、适配器 adapter 模式 加个"适配器" 以便于复用 结构型设计模式

    1.什么是适配器模式? 适配器如同一个常见的变压器,也如同电脑的变压器和插线板之间的电源连接线,他们虽然都是3相的,但是电脑后面的插孔却不能直接插到插线板上. 如果想让额定工作电压是直流12伏特的笔记 ...

  8. 黑马程序员——JAVA基础之简述设计模式

    ------- android培训.java培训.期待与您交流! ---------- 设计模式(Design Patterns) 设计模式(Design pattern)是一套被反复使用.多数人知晓 ...

  9. Java实现23种设计模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

随机推荐

  1. 【IDEA】(4)---很好用的DEBUG功能

    IDEA-DEBUG功能 一.常用快捷键 快捷键并不是完全一样的,我这边是MAC安装的IDEA, 这边最主要还是知道DEBUG时常用的功能. 1.快捷键 F7 #进入下一步,如果当前行是一个方法,则进 ...

  2. Django html页面 'ascii' codec can't encode characters in position 8-10: ordinal not

    用Django开发的页面,之前用的是python3.X,后来又换成python2.X后各种报错,编码问题,于是在所有python文件开头加了编码:#coding=utf-8 但是后来发现,有些文件加了 ...

  3. 前端HTML5思维导图笔记

    看不清的朋友右键保存或者新窗口打开哦!热爱学习前端,喜欢我可以关注我,更多的思维导图笔记

  4. SharedPreferences用法

    SharedPreferences是Android四种数据存储技术中的一种,它是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信 息,其对 ...

  5. js-var变量作用域

    看代码: var a=10; function fn1(){ alert(a); var a=20; alert(a); } 运行结果:undefined 和 20 注意: 在函数内,变量如没用var ...

  6. ★Java语法(四)——————————运算符

    使用除法“/”  ,要特别注意数据类型的问题.若被除数和除数都是整形,且被除数不能被除数整除时,这时输出的结果为整数,(即整形数/整形数=整形数),这是因为整形变量无法保存小数点后面的数据所致,要特别 ...

  7. Deutsch lernen (05)

    1. die Wahrheit, -en 真理:  - 真言,实情 Wir sollen die Wahrheit festhalten. 坚持:紧握 Im Wein liegt Wahrheit. ...

  8. 三维重建7:Visual SLAM算法笔记

    VSLAM研究了几十年,新的东西不是很多,三维重建的VSLAM方法可以用一篇文章总结一下. 此文是一个好的视觉SLAM综述,对视觉SLAM总结比较全面,是SLAM那本书的很好的补充.介绍了基于滤波器的 ...

  9. 团体程序设计天梯赛-练习集-L1-041. 寻找250

    L1-041. 寻找250 对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字. 输入格式: 输入在一行中给出不知道多少个绝对值不超过1000的整数,其中 ...

  10. kipmi0进程单核CPU100%的解决办法

    top查看服务器进程,发现有个kipmi0的进程竟然CPU的单核占用高达100%,而且居高不下. 于是上网搜了搜大家的说法了给出的链接,大概意思是一个固件问题,可以通过修改文件来解决. 专业的解释地址 ...