设计模式---适配器模式

适配器模式

将一个类的接口转换成客户期望的另一个接口,使得原本的接口不兼容的类可以一起工作,结构型设计模式.

适用场景

适配器模式不是设计阶段考虑使用的设计模式,随着软件维护由于接口不相同下的解决方案.

适配器分类

《Head First 设计模式》中提到适配器分为两类:对象适配器,类适配器,此外还有一种==接口适配器==.

对象适配器:使用组合的方式,假设我们需要调用的目标是接口,但是现有的类/接口 和 目标接口不兼容,我们需要一个==适配器==实现目标接口,并且持有 被适配接口/类 对象。

类适配器:类适配器在《Head First 设计模式》中原来指多继承,但是java中,指采用继承的方式,实现目标接口同时继承被适配类,这样继续使用接口的形式调用适配器,从而无感知达到目的。 但是如果被适配类不可知因素过多,使用起来可能 继承效果不如组合来得方便,我的理解假如被适配的类都是通过Spring实例化的,那就有点麻烦了.

接口适配器:接口适配器区别于前面两种,假如一个接口很庞大,我们每次写一个实现类都需要实现所有方法,然后只改写我们用到一两个方法,那代码看起来也会很臃肿,于是就有了接口适配器。 使用抽象类实现接口的所有方法,抽象类实现的接口方法全部是空方法,当新需要一个子类时候,继承抽象类并且只重写特定的方法即可。

简单案例

​ 前几天去了香港,住宿一晚发现,香港电压和内陆是一样的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

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区别是啥)

image

优点

提高类的透明性以及复用, 低耦合,有利于程序扩展;符合开闭

Spring中的适配器

​ 以下是第一次读Spring源码之后对于适配器模式的理解。Spring中有很多Adapter为后缀的类,上面几种形式的适配器很常见对象适配器ConverterAdapter,接口适配器InstantiationAwareBeanPostProcessorAdapterHandlerInterceptorAdapter,当然这些适配器每个作用不相同需要结合源码分析,这里就不记录了,至于==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;
     }
 }

image

FAQ

我好不容易说服了自己HandlerAdapter是适配器模式,如果你能说服我有理有据,欢迎评论告诉我,这块确实纠结了好久!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容