适配器设计模式实战1
一.目的
结合项目源码来深入理解适配器模式,本文通过mybatis3源码中的log适配来介绍适配器模式
二.介绍和作用
适配器模式(Adapter Pattern)
在项目中一般可以将代码分为调用方和提供服务方,一般来说调用方希望使用一个统一的接口来调用服务,而服务方往往来自第三方库或者第三方代码,一般情况下很难做到和本项目的接口代码相兼容,为了解决这种矛盾,采用适配器模式的方式因运而生。
适配器模式的作用:将第三方服务类的接口转换成本项目期望的接口来调用,主的目的是提供兼容性,让接口不匹配不能一起工作的类可以协同工作。也可以称其为包装器(Wrapper)
三.分类
属于结构型模式的一种
再细分的话可分为:类适配器模式、对象适配器模式、接口适配器模式
四.角色划分
Caller调用者类 : 定义客户端所需的接口,可以是抽象类或者接口,也可以是具体类
Adapter适配器 : 适配器可以调用服务方接口,作为一个转换器,对Adaptee和Caller进行适配,
适配器类是适配器模式的核心,在对象适配器中,
Adaptee 服务方类: 被适配的角色
五.代码实现
public class Adapter implements IAdapter { private Adaptee adaptee = new Adaptee(); @Override public void callerMethod() { adaptee.serviceMetho(); } } /** * 提供接口给调用方使用 */ public interface IAdapter { void callerMethod(); } /** * 服务方 */ public class Adaptee { public void serviceMetho(){ System.out.println("第三方服务"); } } /** * 服务调用方 */ public class Caller { public void call(){ IAdapter adapter = new Adapter(); adapter.callerMethod(); } } public class App { public static void main(String[] args) { Caller caller = new Caller(); caller.call(); } }
六.结合Mybatis3中的log适配来
代码实现
public interface ILogAdapter { boolean isDebugEnabled(); boolean isTraceEnabled(); void error(String s, Throwable e); void error(String s); void debug(String s); void trace(String s); void warn(String s); }
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JakartaCommonsLoggingImpl implements ILogAdapter { private final Log log; public JakartaCommonsLoggingImpl(String clazz) { log = LogFactory.getLog(clazz); } @Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } @Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } @Override public void error(String s, Throwable e) { log.error(s, e); } @Override public void error(String s) { log.error(s); } @Override public void debug(String s) { log.debug(s); } @Override public void trace(String s) { log.trace(s); } @Override public void warn(String s) { log.warn(s); } }
import java.util.logging.Level; import java.util.logging.Logger; public class Jdk14LoggingImpl implements ILogAdapter { private final Logger log; public Jdk14LoggingImpl(String clazz) { log = Logger.getLogger(clazz); } @Override public boolean isDebugEnabled() { return log.isLoggable(Level.FINE); } @Override public boolean isTraceEnabled() { return log.isLoggable(Level.FINER); } @Override public void error(String s, Throwable e) { log.log(Level.SEVERE, s, e); } @Override public void error(String s) { log.log(Level.SEVERE, s); } @Override public void debug(String s) { log.log(Level.FINE, s); } @Override public void trace(String s) { log.log(Level.FINER, s); } @Override public void warn(String s) { log.log(Level.WARNING, s); } }
public class Log4jImpl implements ILogAdapter { private static final String FQCN = Log4jImpl.class.getName(); private final Logger log; public Log4jImpl(String clazz) { log = Logger.getLogger(clazz); } @Override public boolean isDebugEnabled() { return log.isDebugEnabled(); } @Override public boolean isTraceEnabled() { return log.isTraceEnabled(); } @Override public void error(String s, Throwable e) { log.log(FQCN, Level.ERROR, s, e); } @Override public void error(String s) { log.log(FQCN, Level.ERROR, s, null); } @Override public void debug(String s) { log.log(FQCN, Level.DEBUG, s, null); } @Override public void trace(String s) { log.log(FQCN, Level.TRACE, s, null); } @Override public void warn(String s) { log.log(FQCN, Level.WARN, s, null); } }
public class StdOutImpl implements ILogAdapter { public StdOutImpl(String clazz) { // Do Nothing } @Override public boolean isDebugEnabled() { return true; } @Override public boolean isTraceEnabled() { return true; } @Override public void error(String s, Throwable e) { System.err.println(s); e.printStackTrace(System.err); } @Override public void error(String s) { System.err.println(s); } @Override public void debug(String s) { System.out.println(s); } @Override public void trace(String s) { System.out.println(s); } @Override public void warn(String s) { System.out.println(s); } }
public class LogFactory { private static Map<String,ILogAdapter> adapterMap = new HashMap<String,ILogAdapter>(); static { adapterMap.put(JakartaCommonsLoggingImpl.class.getName(),new JakartaCommonsLoggingImpl(JakartaCommonsLoggingImpl.class.getName())); adapterMap.put(Jdk14LoggingImpl.class.getName(),new Jdk14LoggingImpl(Jdk14LoggingImpl.class.getName())); adapterMap.put(Log4jImpl.class.getName(),new Log4jImpl(Log4jImpl.class.getName())); adapterMap.put(NoLoggingImpl.class.getName(),new NoLoggingImpl(NoLoggingImpl.class.getName())); adapterMap.put(StdOutImpl.class.getName(),new StdOutImpl(StdOutImpl.class.getName())); } private LogFactory() { // disable construction } public static ILogAdapter getLog(Class<?> clazz) throws LogException { return getLog(clazz.getName()); } public static ILogAdapter getLog(String logger) throws LogException { try { return adapterMap.get(logger); } catch (Throwable t) { throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t); } } }
public class LogFactoryTest { @Test public void shouldUseCommonsLogging() throws LogException { ILogAdapter log = LogFactory.getLog(JakartaCommonsLoggingImpl.class); logSomething(log); assertEquals(log.getClass().getName(), JakartaCommonsLoggingImpl.class.getName()); } @Test public void shouldUseJDK14Logging() throws LogException { ILogAdapter log = LogFactory.getLog(Jdk14LoggingImpl.class); logSomething(log); assertEquals(log.getClass().getName(), Jdk14LoggingImpl.class.getName()); } @Test public void shouldUseLog4jImplLogging() throws LogException { ILogAdapter log = LogFactory.getLog(Log4jImpl.class); logSomething(log); assertEquals(log.getClass().getName(), Log4jImpl.class.getName()); } @Test public void shouldStdOutImplImplLogging() throws LogException { ILogAdapter log = LogFactory.getLog(StdOutImpl.class); logSomething(log); assertEquals(log.getClass().getName(), StdOutImpl.class.getName()); } private void logSomething(ILogAdapter log) { log.warn("Warning message."); log.debug("Debug message."); log.error("Error message."); log.error("Error with Exception.", new Exception("Test exception.")); }
七.代码地址
上述代码地址: https://github.com/arxobject/mybatis_light/tree/master/logAdapter
mybatis3 源码地址 https://github.com/mybatis/mybatis-3