在讲设计模式之前,得先知道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类
这里只分析其中一个实现类,感兴趣的可以去看其它的实现类,基本一致所以这里就不做讲解了
  没有英汉互译结果
  请尝试网页搜索

mybatis原理与设计模式-日志模块- 适配器模式的更多相关文章

  1. MyBatis 源码篇-日志模块1

    在 Java 开发中常用的日志框架有 Log4j.Log4j2.Apache Common Log.java.util.logging.slf4j 等,这些日志框架对外提供的接口各不相同.本章详细描述 ...

  2. MyBatis 源码篇-日志模块2

    上一章的案例,配置日志级别为 debug,执行一个简单的查询操作,会将 JDBC 操作打印出来.本章通过 MyBatis 日志部分源码分析它是如何实现日志打印的. 在 MyBatis 的日志模块中有一 ...

  3. MyBatis 源码篇-插件模块

    本章主要描述 MyBatis 插件模块的原理,从以下两点出发: MyBatis 是如何加载插件配置的? MyBatis 是如何实现用户使用自定义拦截器对 SQL 语句执行过程中的某一点进行拦截的? 示 ...

  4. Mybatis框架基础支持层——日志模块(8)

    前言: java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同.为了统一这些工具的接 ...

  5. myBatis源码解析-日志篇(1)

    上半年在进行知识储备,下半年争取写一点好的博客来记录自己源码之路.在学习源码的路上也掌握了一些设计模式,可所谓一举两得.本次打算写Mybatis的源码解读. 准备工作 1. 下载mybatis源码 下 ...

  6. 【学习转载】MyBatis源码解析——日志记录

    声明:转载自前辈:开心的鱼a1 一 .概述 MyBatis没有提供日志的实现类,需要接入第三方的日志组件,但第三方日志组件都有各自的Log级别,且各不相同,但MyBatis统一提供了trace.deb ...

  7. 【java设计模式】-07适配器模式

    适配器模式 定义: 将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 类型: 结构型模式 应用实例: 1.JAVA JDK 1.1 提供 ...

  8. mybatis源码解析-日志适配器

    1.为什么需要使用适配器?    集成第三方日志组件,屏蔽日志组件底层实现,统一提供写日志的接口. 2.什么是适配器模式 定义:将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法 ...

  9. mybaits源码分析--日志模块(四)

    一.日志模块 首先日志在我们开发过程中占据了一个非常重要的地位,是开发和运维管理之间的桥梁,在Java中的日志框架也非常多,Log4j,Log4j2,Apache Commons Log,java.u ...

随机推荐

  1. 题解 P1017 【进制转换】

    我赶jio这个题难道是让我们写快写? 不管了,赶紧把咕咕咕了一万年的题解写出来. 这个题就是考察负进制和在mod意义下的除法运算的基础运算. (其实也没多大问题) 首先我们先假设一个原始数据\(num ...

  2. Hooking EndScene

    Hey guys, umm i was trying to hook endscene using detours and i used a method that i hooked many oth ...

  3. 深入了解JAVA基础(面试)

    I.常用类型与编码类问题:        1.Java中的基本类型有什么?            byte.short.int.long.float.double.chart.boolean这八种,这 ...

  4. python外星人入侵(游戏开发)

    实现的项目要求: 1.外星人游戏添加飞船上下移动功能: 2.为游戏添加背景音乐: 3.在玩家得分.最高得分.玩家等级前添加"Score"."High Score" ...

  5. Seq2Seq和Attention机制入门介绍

    1.Sequence Generation 1.1.引入 在循环神经网络(RNN)入门详细介绍一文中,我们简单介绍了Seq2Seq,我们在这里展开一下 一个句子是由 characters(字) 或 w ...

  6. web编程非常实用的在线工具大全---转载

    代码对比/归并: http://www.matools.com/compare 正则表达式: http://www.matools.com/regex js/css压缩: http://www.mat ...

  7. PHP pthread多线程

    class test extends Thread { public $arg; public function __construct($arg){ $this->arg = $arg; } ...

  8. redis-3.0.0安装

    redis-3.0.0安装 前言 redis是常用的no-sql数据库,常用于缓存数据,同时,他也可以持久化数据.他是C语言开发的,所以安装的时候需要编译. 单机版redis yum install ...

  9. HDU 1387 Team Queue( 单向链表 )

    Team Queue Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  10. Linux上用sublime编辑Python时候出现"SyntaxError: Non-ASCII character ‘\xe5′ in file"的问题

    Reopen with Encoding UTF-8也没用,那只是在编辑界面里面显示出中文而已,编译的时候还是不能识别中文. 所以,还是按网上说的吧,在每一个有中文的文件第一行加上# -*- codi ...