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 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/429246.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

适合文科女孩子学的计算机类专业,文科女生最吃香的专业2021 哪些专业有前景...

文科女生最吃香的专业2021 哪些专业有前景2021-03-27 14:36:27文/丁雪竹文科女生可以报考的专业并不是很多,小编整理了文科女生吃香的专业,来看一下!文科女生最吃香的专业网络与新媒体这个专业是近几年流行起来的新兴专业,需求量还…

系统搭建遇到问题3:Ubuntu问题造成网卡名称异常导致Vivado绑定网卡地址的Lic无法正常工作(JESD)...

解决方法参考: ubuntu平台vivado无法识别NIC_ID而无法使用license的解决办法 http://blog.csdn.net/cirs_q/article/details/60574030转载于:https://www.cnblogs.com/abolide/p/6920397.html

中职计算机基础知识总结,中职计算机基础知识整理

中职计算机基础知识整理计算机基础知识(初稿2011/10/5)1、计算机发展简史第一代(1946-1957年)电子管第二代(1958-1964年)晶体管第三代(1964-1970年)中、小规模集成电路第四代(1971年至今)大规模和超大规模集成电路2、我国计算机发展我国电子计算机研究工作起步于1956年1958年试…

多个html如何套用套一个头部,Vue.js项目中管理每个页面的头部标签的两种方法...

在 Vue SPA 应用中,如果想要修改 HTML 的头部标签,如页面的 title ,我们只能去修改 index.html 模板文件,但是这个是全局的修改,如何为每个页面都设置不一样的 title 呢?下面介绍两种方法。使用router.Meta…

Ubuntu16.04下Mongodb官网安装部署步骤(图文详解)(博主推荐)

不多说,直接上干货! 在这篇博客里,我采用了非官网的安装步骤,来进行安装。走了弯路,同时,也是不建议。因为在大数据领域和实际生产里,还是要走正规的为好。 Ubuntu16.04下Mongodb(离…

甘肃政法学院计算机科学与技术试题,甘肃政法学院计算机科学与技术专业课程教学大纲.doc...

甘肃政法学院计算机科学与技术专业课程教学大纲甘肃政法学院计算机科学与技术专业课程教学大纲数字逻辑与分析一、说明(一)课程性质(三)教学内容1.了解数字电路和脉冲电路的概念。2.TTL门电路、CMOS两类集成门电路的外部特性:逻辑功能、电器特…

我确实不知道如何使用计算机的英文,用英语介绍我的电脑

篇一:电脑 ComputerComputer is a very useful machine. Some of them are big, but some of them are very small .Many people like playing computer. Computer has many functions, so that people can do a lot of things by computer, like watching movies, …

第二阶段个人工作总结04

昨天做了什么? 优化评论页面。 今天准备做什么? 对点赞修改。 遇到什么困难? 无。转载于:https://www.cnblogs.com/fylove/p/6979899.html

uva 11971 Polygon

https://vjudge.net/problem/UVA-11971 有一根长度为n的木条&#xff0c;随机选k个位置把它们切成k1段小木条。求这些小木条能组成一个多边形的概率。 将木条看做一个圆&#xff0c;线上切k刀等价于圆上切k1刀 如果能组成多边形&#xff0c;每一段木条的长度都要<圆周长/2 反…

计算机修改文字试题,计算机文字处理试题.doc

计算机文字处理试题文字处理单选题1、Word文档文件的扩展名是______。A&#xff1a;txtB&#xff1a;docC&#xff1a;batD&#xff1a;dat答案&#xff1a;B2、Word程序启动后就自动打开一个文档&#xff0c;其文档名为______。A&#xff1a;文档1B&#xff1a;文档0C&#xf…

Charles - 接口抓包分析工具

Charles是一个HTTP代理服务器&#xff0c;反转代理服务器&#xff0c;HTTP监视器。它允许一个开发者查看所有连接互联网的HTTP通信&#xff0c;包括request、 response现HTTP headers &#xff08;包含cookies与caching信息&#xff09;。 下载&#xff1a; http://www.charle…

计算机网络实用期末试题和答案,计算机网络期末考试试题及答案(1)

计算机网络期末考试试题及答案填空题(每空 1 分&#xff0c;共 30 分)1、在计算机网络的定义中&#xff0c;一个计算机网络包含多台具有__自治____功能的计算机&#xff1b;把众多计算机有机连接起来要遵循规定的约定和规则&#xff0c;即__通信协议_____&#xff1b;计算机网络…

微型计算机原理及接口技术林志贵,微型计算机原理及接口技术第七章部分习题答案林志贵主编...

《微型计算机原理及接口技术第七章部分习题答案林志贵主编》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《微型计算机原理及接口技术第七章部分习题答案林志贵主编(7页珍藏版)》请在人人文库网上搜索。1、7-1、I/O接口的信号有哪几种&#xff1f;各有什么特点&#…

表现与数据分离;前台MVC

无意间看到一个web前端招聘要求&#xff1a;表现与数据分离 这名词对我非常陌生&#xff0c;我就去百度了下 由于有各种莫名其妙的需求&#xff0c;所以才会出现我们前端MVC这样的莫名其妙的东西。。。我们的html就是model&#xff0c;我们的css就是view。我们的js就是controll…

街上第一台电子计算机是,南京信息工程大学滨江学院2009级《计算机基础》(文科)a试卷(含答案)【最新】.doc...

南京信息工程大学滨江学院2009级《计算机基础》(文科)a试卷(含答案)【最新】.doc南京信息工程大学滨江学院2009 ─ 2010 学年 第 一 学期计 算 机 基 础(文) 课程试卷试卷类型 A (注明A、B卷) 考试类型 闭卷 (注明开、闭卷)注意&#xff1a;1、本课程为 必修 (注明必修或选修)&…

使用EFI引导从硬盘(U盘)安装Win7的图文教程

眼下仅支持vista后的64位系统大部分使用EFI引导安装Win7的教程都是採用光盘启动安装&#xff0c;尽管光盘安装比較简单&#xff0c;可是对于没有光驱的朋友来说还是相当不便&#xff0c;更不用说光盘安装的两大缺点了&#xff0c;一速度慢&#xff0c;二不灵活。因此本篇教程将…

计算机语言中str是什么意思,vb中str什么意思

vb中str什么意思&#xff1f;str是VB的一种函数&#xff0c;可以将数字型变量或常量转换成字符型变量或常量。str函数的功能是返回代表一数值的Variant (String)。当一数字转成字符串时&#xff0c;总会在前头保留一空位来表示正负。如果 number 为正&#xff0c;返回的字符串包…

基于探究式教学法的计算机网络原理课程的教学改革与实践,基于探究式教学法的“计算机网络原理”课程的教学改革与实践分析...

基于探究式教学法的 “计算机网络原理”课程的教学改革与实践分析张敏莉摘要“&#xff1a;计算机网络原理”课程教学的目标是让学生学习和掌握计算机网络的基本概念、原理、方法以及具体实现技术等基础知识&#xff0c;为学生学习其他计算机专业课程奠定坚实基础。本文在分析“…

异步编程

1、async/await特性结构 异步方法&#xff1a;就是在处理完成之前就返回到调用方法。 async/await特性结构由三个部分构成&#xff1a; (1)调用方法&#xff1a;调用异步方法的那个方法&#xff0c;它和异步方法可能在相同的线程&#xff0c;也可能在不同的线程。在异步方法执行…

预算里怎样计算机械作业费,用实物法编制施工图预算的完整步骤有( )等。 A.计算工程量B.套用预算人工、材料、机械 - 作业在线问答...

相关题目与解析用实物法编制施工图预算的完整步骤有()等。A&#xff0e;计算工程量B&#xff0e;套用预算人工、材料、机械台用实物法编制施工图预算时&#xff0c;分项工程量计算之后的步骤是()。A&#xff0e;套用预算定额单价B&#xff0e;实物量法编制施工图预算的步骤包括…