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

转载于:https://www.cnblogs.com/jhcelue/p/6916363.html

Java读源代码学设计模式:适配器Adapter相关推荐

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

    适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 适配器模式的用途 用电器做例子,笔记本电脑的插头一般都是三相的,即除了阳极.阴极 ...

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

    模式定义 将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 类图 应用场景 1.当你希望使用某些现有类,但其接口与你的其他代码不兼容时: 2 ...

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

    适配器模式 概述 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性 1.你想使用一个已经存在的类,而它的接口不符合你的需 ...

  4. 读源代码学Asp.net Ajax(一)

    本文希望为有一定基础的Asp.net Ajax同学提供另外一个视角,进一步的分析了解Asp.net Ajax的运行机制. 首先,源代码从何而来? 我是用的笨方法(如果大家有好办法,一定给我留言哟!): ...

  5. 重学设计模式--读后总结篇,我理解的设计模式!!(二)

    极力推荐小傅哥的重学设计模式!!! 一.二十三种设计模式 1.二十三种设计模式 1.1 工厂方法模式 1.2 抽象工厂模式 1.3 建造者模式 1.4 原型模式 1.5 单例模式 1.6 适配器模式 ...

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

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

  7. 设计模式学习笔记——适配器(Adapter)模式

    设计模式学习笔记--适配器(Adapter)模式 @(设计模式)[设计模式, 适配器模式, adapter, 适配器] 设计模式学习笔记适配器Adapter模式 基本介绍 适配器案例 类适配器模式 类 ...

  8. 如何定义适配器adapter类_设计模式22-Adapter(适配器)模式-组件接口适配

    在软件开发过程中,有时候系统的数据和行为都正确,但接口不符合,这时候我们就应该考虑使用适配器模式,适配器的作用即将一个类的接口转换成客户希望的另外一个接口.它使得原本由于接口不兼容而不能一起工作的那些 ...

  9. 卢克,学着去读源代码

    读源代码卡住时,就要尝试从外围去看它,如API的结构,框架的设计图. 求知欲,耐心,勇气: 你能读懂吗?你能够读懂的. 跟着线索走 git是一个在开源社区里广泛应用的源代码管理工具.git clone ...

最新文章

  1. 急需降低系统复杂性,我们从 Kafka 迁移到了 Pulsar
  2. 使用dwz框架搭建网站后台
  3. Python学习之路--函数
  4. linux中shell编写数组排序,linux bash shell实现对数组快速排序(升序)
  5. mysql不能访问order,使用ORDER BY时,MySQL不使用索引(“Using filesort”)
  6. flex java 全局拦截_Flex CSS阻止底层内容
  7. 蓝桥杯 ADV-63 算法提高 利息计算
  8. location.host与location.hostname和跨浏览器的兼容性?
  9. [转载] Python简介、linux上Python及其IDE的安装和详细配置
  10. CentOS系统安装FTP服务器
  11. ShuffleNet网络学习笔记
  12. 2021年中国充电桩行业发展环境(PEST)分析:随着新能源汽车的增加,充电桩也随之增加[图]
  13. 深入dwr2-commet模式
  14. java 获取图片后缀_java 自动识别图片文件类型 图片后缀 图片类型
  15. MySQL--- 有哪些“饮鸩止渴”提高性能的方法?
  16. 钉钉发起审批流程分析
  17. 腾讯优图计算机招聘视觉大咖(2022届校招+实习)
  18. Python求最大公倍数
  19. 禅道安装/禅道远程数据库连接
  20. strrchr()函数

热门文章

  1. 在laravel5.8中集成swoole组件----用协程实现的服务端和客户端(nginx配置篇章)
  2. Comet OJ - 2019 六一欢乐赛
  3. PhantomJS 一个隐形的浏览器
  4. BZOJ 4241 分块
  5. Hyperledger中数据存取的实现
  6. 数据库5 索引 动态哈希(Dynamic Hashing)
  7. 【转】WEB前端调优
  8. 影响中国历史的十篇政治美文
  9. 各种推荐资料汇总。。。
  10. PHP 通过设置P3P头来实现跨域访问COOKIE