将一个类的接口转换成客户指望的另外一个接口,使得本来的接口不兼容的类能够一块儿工做,结构型设计模式.spring
适配器模式不是设计阶段考虑使用的设计模式,随着软件维护因为接口不相同下的解决方案.设计模式
《Head First 设计模式》中提到适配器分为两类:对象适配器,类适配器,此外还有一种==接口适配器==.app
对象适配器:使用组合的方式,假设咱们须要调用的目标是接口,可是现有的类/接口 和 目标接口不兼容,咱们须要一个==适配器==实现目标接口,而且持有 被适配接口/类 对象。框架
类适配器:类适配器在《Head First 设计模式》中原来指多继承,可是java中,指采用继承的方式,实现目标接口同时继承被适配类,这样继续使用接口的形式调用适配器,从而无感知达到目的。 可是若是被适配类不可知因素过多,使用起来可能 继承效果不如组合来得方便,个人理解假如被适配的类都是经过Spring
实例化的,那就有点麻烦了.ide
接口适配器:接口适配器区别于前面两种,假如一个接口很庞大,咱们每次写一个实现类都须要实现全部方法,而后只改写咱们用到一两个方法,那代码看起来也会很臃肿,因而就有了接口适配器。 使用抽象类实现接口的全部方法,抽象类实现的接口方法所有是空方法,当新须要一个子类时候,继承抽象类而且只重写特定的方法便可。源码分析
前几天去了香港,住宿一晚发现,香港电压和内陆是同样的220V,50HZ,可是咱们不能直接在插头插上充电线来给手机充电,香港法律规定室内电器插头都是英式的方脚三柱插头,内陆的插头都是两脚插头,像手机充电线插头都是两个平行的脚,这时候使用酒店提供的转换器就能够正常使用充电线了,转换器就像是适配器。这就是对象适配器的一个小例子,内陆标准的充电插头规范(双平行脚)就是咱们的目标接口,可是在香港室内都没有这种提供使用的双脚的充电插槽, 转换器就是适配器,实现了国内插头标准,由于它有 双脚插槽,同时它还组合的 三角的充电插槽,无缝衔接.测试
//国内常见插头接口规范 public interface DoublePin { void chargeForDoublePin(); } //适配器 public class PluginAdaptor implements DoublePin { private TripplePin tripplePin; public PluginAdaptor(final TripplePin tripplePin) { this.tripplePin = tripplePin; } @Override public void chargeForDoublePin() { tripplePin.chargeForThreePinOnly(); } } //香港以及之外的插头规范 public class TripplePin { void chargeForThreePinOnly(){ System.out.println("充电中......"); } }
测试类PersonTests
this
public class PersonTests { public static void main(String[] args) { TripplePin hotelPlugin = new TripplePin(); DoublePin myChargeLine=new PluginAdaptor(hotelPlugin); myChargeLine.chargeForDoublePin(); } }
讲解:适配器的目的至关于中间人,中间人确定要知道有两方信息吧,对象适配器特征:实现目标接口,持有另一方联系;设计
类适配器的例子
public class PluginAdaptor2 extends TripplePin implements DoublePin { @Override public void chargeForDoublePin() { chargeForThreePinOnly(); } }
讲解:上面适配器的代码稍做改动就是类适配器的例子, 不一样之处就是采用继承的方式做为中间人,若是说 酒店转换头是组合的方式, 那继承就比如 把方脚三柱插头和转换头 包裹严实起来,只留个 双脚的插槽暴露出来, 咱们可能感知下来:噢,香港和国内充电没有区别,充电线带过去同样使用。
接口适配器的例子
java.awt
包中的WindowListener
接口定义了几个 窗口的监听事件,WindowAdapter
实现了接口,可是方法全都是空实现的,若是咱们须要关闭窗口时作额外处理,彻底一个匿名内部类而且重写windowClosed
方法便可,代码简洁且效果同样,(之前写awt就没搞明白windowClosing、windowClosed
区别是啥)
提升类的透明性以及复用, 低耦合,有利于程序扩展;符合开闭
如下是第一次读Spring
源码以后对于适配器模式
的理解。Spring中有不少Adapter
为后缀的类,上面几种形式的适配器很常见对象适配器ConverterAdapter
,接口适配器InstantiationAwareBeanPostProcessorAdapter
、HandlerInterceptorAdapter
,固然这些适配器每一个做用不相同须要结合源码分析,这里就不记录了,至于==HandlerAdapter==、==AvisorAdapter==我感受不像是适配器模式,可是是否使用了什么适配器还不太清楚.
==HandlerAdapter== 理解:名称叫处理器适配器,在SpringMvc中的做用呢找到那个 HandlerAdapter , 而后就是 处理请求 。 我以为更像是一种 适配 , 而不是适配器模式 ,也有人 说这更像命令模式,。 前面记录的适配器模式 是将一个接口转换为 另外一个不兼容的接口,供客户端调用; 先说没有==HandlerAdapter==的话该是怎么处理:
获得mapperHandler.getHandler
,以后判断他是个HttpRequestHandler
仍是HandlerMethod
等等, 进行大量IF ELSE 的逻辑处理,若是咱们在框架基础上修改就须要改动源码,不符合开闭原则。 如今就是将 全部的 HandlerAdapter
实现类放到集合中,调support(handler)
来判断是否支持,以后仅仅用这个HandlerAdapter
去反射执行控制器的方法;
纠结了很久, 换个角度想 个人目标是调用这个 处理器的方法,咱们假设存在这样一个接口unamed,这个接口呢用来动态判断处理器类型而且反射调用;而另外一个不兼容的类就是HandlerAdapter
的各类实现类(好比SimpleServletHandlerAdapter 咱们彻底能够写个任意名字方法调用 handle.service(request,response); ) ,如今须要将这个unamed
接口和各个 不兼容的类实现适配, 我会写个类去实现 unamed接口,而后实现handle方法, 可是组合的对象变成 HandlerAdapter
,而且HandlerAdapter是在每次调用这个接口实现类的handle方法以前去动态初始化.
下面这个看起来更是 适配器模式了吧 , 可是下面的代码彻底不必,看起来累赘并且彻底不必。
public interface Unamed { ModelAndView handle1(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; } public class UnamedImpl implements Unamed{ private HandlerAdapter ha; @Override public ModelAndView handle1(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception { ha=getHandler(); return ha.handle(request,response,handler); } private HandlerAdapter getHandler() { //略 return null; } }
我好不容易说服了本身HandlerAdapter
是适配器模式,若是你能说服我有理有据,欢迎评论告诉我,这块确实纠结了很久!