设计模式系列之「适配器模式」

小C:小Y,家里的插孔没有两孔的怎么办?
小Y:so easy,淘宝电源转换插头包邮只要九块九毛九,真的只要九块九毛九。
......
小C:iPhone x变成Lightning接头,传统的耳机会不会用不了?
小Y:又没有这么牛叉的机,你问这个干啥呢(小Y有点不好的预感啊)?买个转换线呗。
小C:哦,没事就问问。

后来呢,小Y几个月只能吃泡面了过日子了,呜呜呜......

其实大家也要学学小Y这种为博红颜一笑,勒紧裤头吃泡面的无谓精神(一定要看好自己的信用卡啊)。言归正传,现实生活中有各种各样的适配器,方便至极,那么,适配器这样的工作,在我们的程序里有吗?答案是必须的,适配器模式。

文章内容思维导图

一、基本概念

1.定义

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。即定义一个包装类,用于包装不兼容接口的对象。

2.应用场景
  • 有动机修改一个已经上线的接口时并且不符合你的需求,适配器模式可能是最适合你的模式。
3.角色介绍
通用UML.png
  • Target目标角色

    该角色定义把其他类转换为何种接口,也就是我们的期望接口。

  • Adaptee源角色

    需要转换成目标角色的源角色,它是已经存在的、运行良好的类或对象,经过适配器角色的包装,它会成为一个崭新的角色。

  • Adapter适配器角色

    适配器模式的核心角色,其他两个角色都是已经存在的角色,而适配器角色是需要新建立的,它的职责非常简单:把源角色通过继承或者类关联的方法转换为目标角色。

二、代码的实现

好了,该是让这次的主角iPhone差的转换线出场了(无限心伤中.....)

在这之前还需要知道适配器模式的形式分为:类的适配器模式对象的适配器模式

1.两种不同形式适配模式的UML对比

两者的差别就是一个是通过继承,一个是通过组合,利用实例的方式去进行

2.两种不同形式适配模式的代码实现

(1)两者实现代码的相同部分

①iPhone X手机接口(Target接口)

public interface PhoneInterface {  
    /**  
     * Lightning耳机接口
    */  
    void lightningHeadSet();  
}  

②Lightning接口耳机

public class LightningHeadSet implements PhoneInterface {  
    @Override  
    public void lightningHeadSet() {  
        System.out.print("使用Lightning接口的耳机连接。");  
    }  
}  

③传统耳机接口(源类Adaptee)

public interface TraditionPhoneInterface {   
    /**  
     * 传统耳机接口  
     */  
    void traditionHeadSet();  
}  

④传统接口耳机

public class TraditionHeadSet implements TraditionPhoneInterface{  

    @Override  
    public void traditionHeadSet() {  
        System.out.print("使用传统接口的耳机连接。");  
    }  
}  

(2)类的适配器模式的实现

创建适配器类(继承传统耳机(源类)和实现Linghtning接口(Target))

public class HeadSetAdapter extends TraditionHeadSet implements PhoneInterface{  
    @Override  
    public void lightningHeadSet() {  
        super.traditionHeadSet();  
    }  
}  

为什么会去继承TraditionHeadSet和实现PhoneInterface呢?是因为用户最终是需要用到Lightning接口去实现听歌,所以要调用lightningHeadSet(),但是适配器的作用就是让传统耳机实现Lightning的转化,最终用传统耳机都能够得到连接。

(3)对象的适配器模式的实现(推荐)

public class ObjectHeadSetAdapter implements PhoneInterface {  

    private TraditionPhoneInterface traditionHeadSet;  

    public ObjectHeadSetAdapter(TraditionPhoneInterface traditionHeadSet) {  
        this.traditionHeadSet=traditionHeadSet;  
    }  

    @Override  
    public void lightningHeadSet() {  
        traditionHeadSet.traditionHeadSet();  
    }  
}  

为什么只实现PhoneInterface接口的理由同上。

(4)客户端输出

public class Client {
    public static void main(String[] args){
        //直接通过lightning接口连接
        LightningHeadSet lightningHeadSet=new LightningHeadSet();
        lightningHeadSet.lightningHeadSet();
        //通过类的适配器进行连接
        HeadSetAdapter headSetAdapter=new HeadSetAdapter();
        headSetAdapter.lightningHeadSet();
        //通过对象的适配器进行连接
        TraditionPhoneInterface traditionSet=new TraditionHeadSet();
        ObjectHeadSetAdapter objectHeadSetAdapter=new ObjectHeadSetAdapter(traditionSet);
        objectHeadSetAdapter.lightningHeadSet();
    }
}

输出的结果为:

①使用Lightning接口的耳机连接。  
②使用传统接口的耳机连接。  
③使用传统接口的耳机连接。  

3.对象的适配器 vs 类的适配器

  • 类的适配器中Adapter与Adaptee是继承关系,因为java是不支持多继承的,因此不适合出现多个源类;对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类,这种关联的方法可以动态组合多个源类。
  • 类的适配器是继承被适配类,所以相对静态;而对象的适配器包含被适配类,所以相对灵活。
  • 类的适配器通过 Override 来扩展新需求;而对象的适配器因为包含关系所以不能扩展。

三、优缺点

1.类的适配器的优缺点

(1)优点

  • 使用方便,代码简化,不需要引入对象实例。

(2)缺点

  • 高耦合,灵活性低。使用对象继承的方式,是静态的定义方式。

2.对象的适配器的优缺点

(1)优点

  • 灵活性高、低耦合 ,采用 “对象组合”的方式,是动态组合方式。

(2)缺点

  • 使用复杂,需要引入对象实例。

3.适配器的优缺点

(1)优点

  • 提高了类的复用度。源角色在原有的系统中可以正常使用,在目标角色中又可以充当新的角色。
  • 增加了类的透明性,客户端可以调用同一接口,因而对客户端来说是透明的。
  • 灵活性好。增加删除不影响原有代码。
  • 符合开闭原则。

(2)缺点

  • 过多的使用适配器,会让系统非常零乱,不易整体进行把握。

四、总结

在选用适配器模式的时候根据需要来选用合适的实现方式,尽量使用对象的适配器模式,多用动态组合合、少用继承

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