适配器模式

菜鸟教程笔记-计算机读取SD卡例子

先模拟计算机读取SD卡:

1、先创建一个SD卡的接口:

public interface SDCard {
//读取SD卡方法
String readSD();
//写入SD卡功能
int writeSD(String msg);
}

2、创建SD卡接口的实现类,模拟SD卡的功能:

public class SDCardImpl implements SDCard {
@Override
public String readSD() {
String msg = "sdcard read a msg :hello word SD";
return msg;
}
@Override
public int writeSD(String msg) {
System.out.println("sd card write msg : " + msg);
return 1;
}
}

3、创建计算机接口,计算机提供读取SD卡方法:

public interface Computer {    
String readSD(SDCard sdCard);
}

4、创建一个计算机实例,实现计算机接口,并实现其读取SD卡方法:

public class ThinkpadComputer implements Computer {
@Override
public String readSD(SDCard sdCard) {
if(sdCard == null)throw new NullPointerException("sd card null");
return sdCard.readSD();
}
}

5、这时候就可以模拟计算机读取SD卡功能:

public class ComputerReadDemo {    
public static void main(String[] args) {
Computer computer = new ThinkpadComputer();
SDCard sdCard = new SDCardImpl();
System.out.println(computer.readSD(sdCard));
}
}

接下来在不改变计算机读取SD卡接口的情况下,通过适配器模式读取TF卡:

1、创建TF卡接口:

public interface TFCard {    
String readTF();
int writeTF(String msg);
}

2、创建TF卡实例:

public class TFCardImpl implements TFCard {    
@Override
public String readTF() {
String msg ="tf card reade msg : hello word tf card";
return msg;
}
@Override
public int writeTF(String msg) {
System.out.println("tf card write a msg : " + msg);
return 1;
}
}

3、创建SD适配TF (也可以说是SD兼容TF,相当于读卡器):
实现SDCard接口,并将要适配的对象作为适配器的属性引入。

对象适配器

public class SDObjectAdapterTF implements SDCard {    
private TFCard tfCard;
public SDAdapterTF(TFCard tfCard) {
this.tfCard = tfCard;
}
@Override
public String readSD() {
System.out.println("adapter read tf card ");
return tfCard.readTF();
}
@Override
public int writeSD(String msg) {
System.out.println("adapter write tf card");
return tfCard.writeTF(msg);
}
}

类适配器

public class SDClassAdapterTF extends TFCardImpl implements SDCard {    

@Override
public String readSD() {
System.out.println("adapter read tf card ");
return readTF();
}
@Override
public int writeSD(String msg) {
System.out.println("adapter write tf card");
return writeTF(msg);
}
}

4、通过上面的例子测试计算机通过SD读卡器读取TF卡:

public class ComputerReadDemo {    
public static void main(String[] args) {
Computer computer = new ThinkpadComputer();
SDCard sdCard = new SDCardImpl();
System.out.println(computer.readSD(sdCard));
System.out.println("====================================");
TFCard tfCard = new TFCardImpl();
//对象适配器
SDCard tfCardObjectAdapterSD = new SDObjectAdapterTF(tfCard);
System.out.println(computer.readSD(tfCardObjectAdapterSD));
//类适配器
SDCard tfCardClassAdapterSD = new SDClassAdapterTF();
System.out.println(computer.readSD(tfCardClassAdapterSD));
}
}

输出:

sdcard read a msg :hello word SD
====================================
adapter read tf card
tf card reade msg : hello word tf card

在这种模式下,计算机并不需要知道具体是什么卡,只需要负责操作接口即可,具体操作的什么类,由适配器决定。

适配器设计模式UML类图

适配器设计模式UML类图

适配器设计模式java实现

/**
* The interface expected by the client.<br> A rowing boat is rowed to move.
*/
public interface RowingBoat {

void row();

}

/**
* The Captain uses {@link RowingBoat} to sail. <br> This is the client in the pattern.
*/
public final class Captain {

private RowingBoat rowingBoat;

public Captain() {
}

public Captain(final RowingBoat boat) {
this.rowingBoat = boat;
}

void setRowingBoat(final RowingBoat boat) {
this.rowingBoat = boat;
}

void row() {
rowingBoat.row();
}

}

/**
* Device class (adaptee in the pattern). We want to reuse this class. Fishing boat moves by
* sailing.
*/
final class FishingBoat {

private static final Logger LOGGER = getLogger(FishingBoat.class);

void sail() {
LOGGER.info("The fishing boat is sailing");
}

}

/**
* Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link RowingBoat}
* interface expected by the client ({@link Captain}).
*/
public class FishingBoatAdapter implements RowingBoat {

private FishingBoat boat;

public FishingBoatAdapter() {
boat = new FishingBoat();
}

public final void row() {
boat.sail();
}
}

/**
* An adapter helps two incompatible interfaces to work together. This is the real world definition
* for an adapter. Interfaces may be incompatible but the inner functionality should suit the need.
* The Adapter design pattern allows otherwise incompatible classes to work together by converting
* the interface of one class into an interface expected by the clients.
*
* <p>There are two variations of the Adapter pattern: The class adapter implements the adaptee's
* interface whereas the object adapter uses composition to contain the adaptee in the adapter
* object. This example uses the object adapter approach.
*
* <p>The Adapter ({@link FishingBoatAdapter}) converts the interface of the adaptee class ({@link
* FishingBoat}) into a suitable one expected by the client ({@link RowingBoat}).
*
* <p>The story of this implementation is this. <br> Pirates are coming! we need a {@link
* RowingBoat} to flee! We have a {@link FishingBoat} and our captain. We have no time to make up a
* new ship! we need to reuse this {@link FishingBoat}. The captain needs a rowing boat which he can
* operate. The spec is in {@link RowingBoat}. We will use the Adapter pattern to reuse {@link
* FishingBoat}.
适配器可帮助两个不兼容的接口一起工作。这是适配器的真实定义。接口可能不兼容,但内部功能应满足需要。适配器设计模式允许将不兼容的类通过将一个类的接口转换为客户端期望的接口来协同工作。
<p> Adapter模式有两种变体:类适配器实现适配器的接口,而对象适配器使用合成器将适配器包含在适配器中
宾语。本示例使用对象适配器方法。
<p>适配器({@link FishingBoatAdapter})将适配器类({@link FishingBoat})的接口转换为客户端期望的合适接口({@link RowingBoat})。
<p>这个实现的故事是这样的。 <br>海盗来了!我们需要一个{@link
RowingBoat}逃离!我们有一个{@link FishingBoat}和我们的队长。我们没有时间下新船!我们需要重用此{@link FishingBoat}。船长需要一艘他可以操作的划艇。规范位于{@link RowingBoat}中。我们将使用Adapter模式来重用{@link FishingBoat}。
*/
public final class App {

private App() {
}

/**
* Program entry point.
*
* @param args command line args
*/
public static void main(final String[] args) {
// The captain can only operate rowing boats but with adapter he is able to
// use fishing boats as well
var captain = new Captain(new FishingBoatAdapter());
captain.row();
}
}

应用场景

spring AOP中的适配器模式

在Spring的Aop中,使用的 Advice(通知) 来增强被代理类的功能。
Advice的类型有:MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice
在每个类型 Advice 都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
Spring需要将每个 Advice 都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对 Advice 进行转换
三个适配者类 Adaptee 如下:

public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method var1, Object[] var2, @Nullable Object var3) throws Throwable;
}

public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object var1, Method var2, Object[] var3, @Nullable Object var4) throws Throwable;
}

public interface ThrowsAdvice extends AfterAdvice {
}

AdvisorAdapter
目标接口 Target,有两个方法,一个判断 Advice 类型是否匹配,一个是工厂方法,创建对应类型的 Advice 对应的拦截器

public interface AdvisorAdapter {
boolean supportsAdvice(Advice var1);

MethodInterceptor getInterceptor(Advisor var1);
}

三个适配器类 Adapter 分别如下,注意其中的 Advice、Adapter、Interceptor之间的对应关系

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}

@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}

@SuppressWarnings("serial")
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
}

class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof ThrowsAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
}

客户端 DefaultAdvisorAdapterRegistry

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList(3);

public DefaultAdvisorAdapterRegistry() {
// 这里注册了适配器
this.registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
this.registerAdvisorAdapter(new AfterReturningAdviceAdapter());
this.registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor)advice);
}

Iterator var4 = this.adapters.iterator();

while(var4.hasNext()) {
AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
if (adapter.supportsAdvice(advice)) { // 这里调用适配器方法
interceptors.add(adapter.getInterceptor(advisor)); // 这里调用适配器方法
}
}

if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
} else {
return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
}
}
// ...省略...
}

这里看 while 循环里,逐个取出注册的适配器,调用 supportsAdvice() 方法来判断 Advice 对应的类型,然后调用 getInterceptor() 创建对应类型的拦截器
这里应该属于对象适配器模式,关键字 instanceof 可看成是 Advice 的方法,不过这里的 Advice 对象是从外部传进来,而不是成员属性

spring JPA中的适配器模式

在Spring的ORM包中,对于JPA的支持也是采用了适配器模式,首先定义了一个接口的 JpaVendorAdapter,然后不同的持久层框架都实现此接口。
jpaVendorAdapter:用于设置实现厂商JPA实现的特定属性,如设置Hibernate的是否自动生成DDL的属性generateDdl;这些属性是厂商特定的,因此最好在这里设置;目前Spring提供 HibernateJpaVendorAdapter、OpenJpaVendorAdapter、EclipseLinkJpaVendorAdapter、TopLinkJpaVendorAdapter 四个实现。其中最重要的属性是 database,用来指定使用的数据库类型,从而能根据数据库类型来决定比如如何将数据库特定异常转换为Spring的一致性异常,目前支持如下数据库(DB2、DERBY、H2、HSQL、INFORMIX、MYSQL、ORACLE、POSTGRESQL、SQL_SERVER、SYBASE)

public interface JpaVendorAdapter
{
// 返回一个具体的持久层提供者
public abstract PersistenceProvider getPersistenceProvider();

// 返回持久层提供者的包名
public abstract String getPersistenceProviderRootPackage();

// 返回持久层提供者的属性
public abstract Map<String, ?> getJpaPropertyMap();

// 返回JpaDialect
public abstract JpaDialect getJpaDialect();

// 返回持久层管理器工厂
public abstract Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface();

// 返回持久层管理器
public abstract Class<? extends EntityManager> getEntityManagerInterface();

// 自定义回调方法
public abstract void postProcessEntityManagerFactory(EntityManagerFactory paramEntityManagerFactory);
}

我们来看其中一个适配器实现类 HibernateJpaVendorAdapter

public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
//设定持久层提供者
private final PersistenceProvider persistenceProvider;
//设定持久层方言
private final JpaDialect jpaDialect;

public HibernateJpaVendorAdapter() {
this.persistenceProvider = new HibernatePersistence();
this.jpaDialect = new HibernateJpaDialect();
}

//返回持久层方言
public PersistenceProvider getPersistenceProvider() {
return this.persistenceProvider;
}

//返回持久层提供者
public String getPersistenceProviderRootPackage() {
return "org.hibernate";
}

//返回JPA的属性
public Map<String, Object> getJpaPropertyMap() {
Map jpaProperties = new HashMap();

if (getDatabasePlatform() != null) {
jpaProperties.put("hibernate.dialect", getDatabasePlatform());
} else if (getDatabase() != null) {
Class databaseDialectClass = determineDatabaseDialectClass(getDatabase());
if (databaseDialectClass != null) {
jpaProperties.put("hibernate.dialect",
databaseDialectClass.getName());
}
}

if (isGenerateDdl()) {
jpaProperties.put("hibernate.hbm2ddl.auto", "update");
}
if (isShowSql()) {
jpaProperties.put("hibernate.show_sql", "true");
}

return jpaProperties;
}

//设定数据库
protected Class determineDatabaseDialectClass(Database database)
{
switch (1.$SwitchMap$org$springframework$orm$jpa$vendor$Database[database.ordinal()])
{
case 1:
return DB2Dialect.class;
case 2:
return DerbyDialect.class;
case 3:
return H2Dialect.class;
case 4:
return HSQLDialect.class;
case 5:
return InformixDialect.class;
case 6:
return MySQLDialect.class;
case 7:
return Oracle9iDialect.class;
case 8:
return PostgreSQLDialect.class;
case 9:
return SQLServerDialect.class;
case 10:
return SybaseDialect.class; }
return null;
}

//返回JPA方言
public JpaDialect getJpaDialect() {
return this.jpaDialect;
}

//返回JPA实体管理器工厂
public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() {
return HibernateEntityManagerFactory.class;
}

//返回JPA实体管理器
public Class<? extends EntityManager> getEntityManagerInterface() {
return HibernateEntityManager.class;
}
}

配置文件中可以这样指定

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
<property name="generateDdl" value="false" />
<property name="database" value="HSQL"/>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

spring MVC中的适配器模式

Spring MVC中的适配器模式主要用于执行目标 Controller 中的请求处理方法。
在Spring MVC中,DispatcherServlet 作为用户,HandlerAdapter 作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller 作为需要适配的类。
为什么要在 Spring MVC 中使用适配器模式?Spring MVC 中的 Controller 种类众多,不同类型的 Controller 通过不同的方法来对请求进行处理。如果不利用适配器模式的话,DispatcherServlet 直接获取对应类型的 Controller,需要的自行来判断,像下面这段代码一样:

if(mappedHandler.getHandler() instanceof MultiActionController){  
((MultiActionController)mappedHandler.getHandler()).xxx
}else if(mappedHandler.getHandler() instanceof XXX){
...
}else if(...){
...
}

这样假设如果我们增加一个 HardController,就要在代码中加入一行 if(mappedHandler.getHandler() instanceof HardController),这种形式就使得程序难以维护,也违反了设计模式中的开闭原则 – 对扩展开放,对修改关闭。
我们来看看源码,首先是适配器接口 HandlerAdapter

public interface HandlerAdapter {
boolean supports(Object var1);

ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

long getLastModified(HttpServletRequest var1, Object var2);
}

现该接口的适配器每一个 Controller 都有一个适配器与之对应,这样的话,每自定义一个 Controller 需要定义一个实现 HandlerAdapter 的适配器。
springmvc 中提供的 Controller 实现类有如下
Controller
springmvc 中提供的 HandlerAdapter 实现类如下
HandlerAdapter
HttpRequestHandlerAdapter 这个适配器代码如下

public class HttpRequestHandlerAdapter implements HandlerAdapter {
public HttpRequestHandlerAdapter() {
}

public boolean supports(Object handler) {
return handler instanceof HttpRequestHandler;
}

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
((HttpRequestHandler)handler).handleRequest(request, response);
return null;
}

public long getLastModified(HttpServletRequest request, Object handler) {
return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
}
}

当Spring容器启动后,会将所有定义好的适配器对象存放在一个List集合中,当一个请求来临时,DispatcherServlet 会通过 handler 的类型找到对应适配器,并将该适配器对象返回给用户,然后就可以统一通过适配器的 hanle() 方法来调用 Controller 中的用于处理请求的方法。

public class DispatcherServlet extends FrameworkServlet {
private List<HandlerAdapter> handlerAdapters;

//初始化handlerAdapters
private void initHandlerAdapters(ApplicationContext context) {
//..省略...
}

// 遍历所有的 HandlerAdapters,通过 supports 判断找到匹配的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}

// 分发请求,请求需要找到匹配的适配器来处理
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);

// 确定当前请求的匹配的适配器.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

ha.getLastModified(request, mappedHandler.getHandler());

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
// ...省略...
}

通过适配器模式我们将所有的 controller 统一交给 HandlerAdapter 处理,免去了写大量的 if-else 语句对 Controller 进行判断,也更利于扩展新的 Controller 类型。