适配器模式

1、定义:

       将一个类的接口转换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

2、使用场景:

       客户端需要一个target(目标)接口,但是不能直接重用已经存在的adaptee(适配者)类,因为它的接口和和target接口不一致,所以需要用adapter(适配器)adaptee转换为target接口。前提是target接口和已存在的适配者adaptee类所做的事情是相同或相似,只是接口不同且都不易修改。如果在设计之初,最好不要考虑这种设计模式。凡事都有例外,就是设计新系统的时候考虑使用第三方组件,因为我们就没必要为了迎合它修改自己的设计风格,可以尝试使用适配器模式

这是一个适配器使用场景的例子:

       Sun公司在1996年公开了Java语言的数据库连接工具JDBCJDBC使得Java语言程序能够与数据库连接,并使用SQL语言来查询和操作数据。JDBC给出一个客户端通用的抽象接口,每一个具体数据库引擎(如SQL ServerOracleMySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。抽象的JDBC接口和各个数据库引擎API之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的驱动程序。

3、优点:       

类适配器模式:

       由于适配器adapter类是适配者adaptee类的子类,因此可以在适配器类中置换一些适配者的方法,即Override(重写),使得适配器的灵活性更强。

对象适配器模式:

       一个对象适配器可以把多个不同的适配者adaptee适配到一个目标,也就是说,同一个适配器可以将适配者类和它的子类都适配到目标接口。

4、缺点:

类适配器模式:

       java8之前:接口没有default方法,就是没有实现了具体逻辑的方法,而且不支持类多继承,所以适配者类只能有一个。

       java8之后:接口有了default方法,接口中的方法有了实现,因为接口是多继承的,所以适配者可以是多个带有default方法的接口,但是接口是不可以实例化的,实际上没有什么意义。有个解决方法就是,接口里都是default方法,实现接口的类什么也没做,就是提供一个可以实例化的类。这样的化,类适配器模式中适配者adapter类就可以适配多个适配者adaptee类了。这个解决方法只是我理论上论证一下,实际上可行与否,请自行判断验证。

对象适配器模式:

       类适配器模式的优点就是对象适配器模式的缺点,不能置换适配者类的方法。如果想修改适配者类的一个或多个方法,就只好先创建一个继承与适配者类的子类,把适配者类的方法置换掉,然后把适配者的子类当做真正的适配者进行适配,实现过程较为复杂。

5、结构组成

       1、目标角色(Target):客户期待得到的东西,目标可以是具体的或抽象的类,也可以是接口

       2、适配者角色(Adaptee):已有接口,但是和客户器期待的接口不兼容。

       3、适配器角色(Adapter):将已有接口转换成目标接口。

6、适配器模式分类

       1、类适配器:通过继承来实现适配器功能。

       2、对象适配器:通过组合来实现适配器功能。

类适配器:

一、关系图

二、示例代码展示

       目标Target代码如下:

/*
 * Target(目标):用户所期待的想要的东西
 * */
public interface Target {
    /*想要得到的东西*/
    int request();
}

       Adaptee代码如下:

/*
 * Adaptee(源):已有接口,但是和客户器期待的接口不兼容
 * */
public class Adaptee {
	
	public int specificRequest() {
	    return 220;
	}
}

       适配器Adapter代码如下:

/*
 * Adapter(适配器):将已有接口转换成目标接口。
 * */
public class Adapter extends Adaptee implements Target{
    
        /*实现目标方法*/
	@Override
	public int request() {
	    return specificRequest()/44;
	}
}

       客户端Client代码如下:

/*
 * 客户端
 * */
public class Client {
	
	public static void main(String[] args) {
		
                /*创建一个目标对象*/
		Target target = new Adapter();
		System.out.println(target.request());
	}
}

       输出结果如下:

       具体实例展示:变压器我们大家都知道,就是将高电压转换成低电压,常见的小型变压器就是我们的手机充电器,接下来我们就以变压器 为例,展示一下类适配器模式。 

       目标角色target

/*目标角色target*/
public interface PowerTarget {
	public int output5V();
}

       适配者角色adaptee: 

/*适配者角色*/
public class PowerAdaptee {
	private int output =  220;
	public int output220V() {
	    System.out.println("电源输出电压:" + output);
	    return output;
	}
}

       适配器角色adapter: 

/*适配器角色*/
public class PowerAdapter extends PowerAdaptee implements PowerTarget{

	@Override
	public int output5V() {
	    int result = output220V()/44;
	    System.out.println("此时的输出电压为:"+result);
	    return result;
	}
}

       类适配器模式测试类 :

/*类适配器模拟测试类*/
public class ClassAdapterPatternTest {

	public static void main(String[] args) {
	    PowerTarget target = new PowerAdapter();
	    target.output5V();
	}
}

       输出结果: 

对象适配器:

一、关系图

二、示例代码展示

       目标Target代码如下:

/*
 * Target(目标):用户所期待的想要的东西
 * */
public interface Target {
    /*想要得到的东西*/
    int request();
}

       Adaptee代码如下:

/*
 * Adaptee(源):已有接口,但是和客户器期待的接口不兼容
 * */
public class Adaptee {
	
	public int specificRequest() {
	    return 220;
	}
}

       适配器Adapter代码如下:

/*
 * Adapter(适配器)
 * */
public class Adapter  implements Target{

	private Adaptee adaptee = new Adaptee();
	
	@Override
	public int request() {
        return adaptee.specificRequest()/44;	
	}
}

       客户端Client代码如下:

/*
 * 客户端
 * */
public class Client {
	
	public static void main(String[] args) {
		
                /*创建一个目标对象*/
		Target target = new Adapter();
		System.out.println(target.request());		
	}
}

       输出结果如下:

       具体实例展示:对象适配器类适配器模式只有Adapter类有不同,其他完成一样,连测试结果都是一样。下面只贴上Adapter类,实现了PowerTarget(目标角色),在创建对象时引入PowerAdaptee(适配者角色)

public class PowerAdapter2 implements PowerTarget{
	private PowerAdaptee powerAdaptee;
	public PowerAdapter2(PowerAdaptee powerAdaptee) {
		super();
		this.powerAdaptee = powerAdaptee;
	}
	@Override
	public int output5V() {
		int result = powerAdaptee.output220V()/44;
		System.out.println("此时的输出电压为:"+result);
		return result;
	}
}

7、典型应用

一、spring AOP中的适配器模式     

       在SpringAop中,使用的 Advice(通知)来增强被代理类的功能。常见的通知类型有前置通知、后置通知、返回后通知等等。每个类型 Advice 都有对应的拦截器。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 {
}

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

public interface AdvisorAdapter {
    boolean supportsAdvice(Advice var1);

    MethodInterceptor getInterceptor(Advisor var1);
}

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

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 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 实现类有如下:

       springmvc 中提供的 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 类型。

三、spring JPA中的适配器模式

       在SpringORM包中,对于JPA的支持也是采用了适配器模式,首先定义了一个接口的 JpaVendorAdapter,然后不同的持久层框架都实现此接口。

       jpaVendorAdapter:用于设置实现厂商JPA实现的特定属性,如设置Hibernate的是否自动生成DDL的属性generateDdl;这些属性是厂商特定的,因此最好在这里设置。

       目前Spring提供 HibernateJpaVendorAdapterOpenJpaVendorAdapterEclipseLinkJpaVendorAdapterTopLinkJpaVendorAdapter 四个实现。其中最重要的属性是 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"/>  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐的小三菊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值