一、适配器模式三种情况

适配器模式,顾名思义,就是把原本不兼容的接口,通过适配,使之兼容。

举个生活中简单的例子,以前的手机内存卡可以取出来,但是想和电脑之间传输音乐、视频等资料不能直接传输,需要通过USB读卡器,然后插入USB接口就可以传输了,这个USB读卡器就相当于适配器。

你经常使用的手机或电脑充电器,也属于适配器,它将220V的交流电转换为手机可用的直流电。下面,以手机充电器为例讲解适配器模式。

适配器模式一般分为三类:类适配器模式、对象适配器模式、接口适配器模式(缺省适配器模式)

1.类适配器模式

一般手机充电器输出的直流电压为5V,我们把交流电220V称为源,希望得到的直流电5V称为目标,而充电器即为适配器。

//源,交流电
public class AC {public int outputAC(){return 220;}
}
//目标接口,直流电
public interface IDC {public int outputDC();
}
//适配器
public class ClsAdapter extends AC implements IDC{@Overridepublic int outputDC() {return outputAC()/44;  //直流电为交流电的电压值除以44}public static void main(String[] args) {ClsAdapter adapter = new ClsAdapter();System.out.println("交流电电压:" + adapter.outputAC());System.out.println("直流电电压:" + adapter.outputDC());}
}/**
输出结果为:
交流电电压:220
直流电电压:5
*/

2.适配器模式
对象适配器,不是继承源类,而是依据关联关系,持有源类的对象,这也隐藏了源类的方法。在这里,适配器和源类的关系不是继承关系,而是组合关系。

public class ObjAdapter implements IDC {//持有源类的对象private AC ac;public ObjAdapter(AC ac){this.ac = ac;}public int outputAC(){return ac.outputAC();}@Overridepublic int outputDC() {return ac.outputAC()/44;}public static void main(String[] args) {ObjAdapter adapter = new ObjAdapter(new AC());System.out.println("交流电电压:" + adapter.outputAC());System.out.println("直流电电压:" + adapter.outputDC());}
}
//输出结果同上

3、接口适配器模式

设想,我现在的目标接口有多个方法,可以输出5V,12V,20V的电压。按照正常逻辑,设计一个适配器去实现这个接口,很显然需要实现所有的方法。但是,实际使用中,其实只需要使用其中一个方法就可以了,比如我mac电脑直流电压20V,只需要实现20V的方法就可以了。

因此,设计一个中间类去把目标接口的所有方法空实现,然后适配器类再去继承这个中间类,选择性重写我所需要的方法,岂不是更好。代码如下,

//目标接口,有多个方法
public interface IDCOutput {public int output5V();public int output12V();public int output20V();
}
//中间类,空实现所有方法,这是一个抽象类
public abstract class DefaultAdapter implements IDCOutput {@Overridepublic int output5V() {return 0;}@Overridepublic int output12V() {return 0;}@Overridepublic int output20V() {return 0;}
}
//我的mac电源适配器只需要实现20V的方法即可
public class MacAdatper extends DefaultAdapter {private AC ac;public MacAdatper(AC ac){this.ac = ac;}@Overridepublic int output20V() {return ac.outputAC()/11;}public static void main(String[] args) {MacAdatper adatper = new MacAdatper(new AC());System.out.println("mac电脑电压:" + adatper.output20V());}
}
//输出结果:
//mac电脑电压:20

至于为什么中间类使用抽象类,相信你看过我介绍的软件六大设计原则,就明白了。它需要符合里氏替换原则(尽量基于抽象类和接口的继承)。

不太明白接口适配模式的童鞋,建议看一下JDK里边提供的一个键盘监听适配器KeyAdapter,它就是一个抽象类,去空实现了KeyListener接口的所有方法。你就会感受到这种模式的奥妙。

总结:

  • 类适配器模式,继承源类,实现目标接口。
  • 对象适配器模式,持有源类的对象,把继承关系改变为组合关系。
  • 接口适配器模式,借助中间抽象类空实现目标接口所有方法,适配器选择性重写。

三种模式,各有优缺点,可根据实际情况选择使用。

二、桥接模式

抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

桥接模式示例

下面我们以发消息为例来进行说明,首先消息类型是一个维度,比如可以发邮件,发短信。然后消息可以有紧急消息,普通消息,这又是一个具体的维度。

1、首先新建一个消息接口类:

package com.zwx.design.pattern.bridge;public interface IMessage {void send(String content,String toUser);
}

2、新建两个实现类,分别是邮件消息和短信消息:

package com.zwx.design.pattern.bridge;public class EmailMessage implements IMessage {@Overridepublic void send(String content, String toUser) {System.out.println(String.format("邮件消息->%s:%s",toUser,content));}
}
package com.zwx.design.pattern.bridge;public class SmsMessage implements IMessage {@Overridepublic void send(String content, String toUser) {System.out.println(String.format("SMS消息->%s:%s",toUser,content));}
}

假如这时候我们需要按照普通消息和紧急消息来做一些不同的事情,那么这时候普通写法会怎么写,我想可能会是如下写法,直接改写消息类,在分别去实现紧急消息类和普通消息类:

public class SmsMessage extends CommonMsg implements IMessage {

但是Java是单继承,所以一次只能继承一个,要么就把普通消息和紧急消息设置为接口,要么就作为组合的形式,将紧急消息和普通消息分别作为属性存到对应的消息类型里面去。但是不论是哪种形式,都需要修改原先的SmsMessage 类。

所以这时候就需要使用桥接模式,将抽象(消息类型)与实现(消息紧急程度)进行分离。

3、新建一个抽象类,将IMessage集成进去:

package com.zwx.design.pattern.bridge;public abstract class AbstractMessage {private IMessage iMessage;public AbstractMessage(IMessage iMessage) {this.iMessage = iMessage;}public void sendMessage(String content,String toUser){this.iMessage.send(content,toUser);}
}

4、新建一个紧急程度为普通的消息类:

package com.zwx.design.pattern.bridge;public class CommonMsg extends AbstractMessage {public CommonMsg(IMessage iMessage) {super(iMessage);}@Overridepublic void sendMessage(String content, String toUser) {this.doSomething();super.sendMessage(content, toUser);}private void doSomething() {System.out.println("这只是一个普通消息");}
}

5、新建一个紧急程度为紧急的消息类:

package com.zwx.design.pattern.bridge;public class UrgentMessage extends AbstractMessage{public UrgentMessage(IMessage iMessage) {super(iMessage);}@Overridepublic void sendMessage(String content, String toUser) {doSomething();super.sendMessage(content, toUser);}private void doSomething() {System.out.println("这是紧急消息,请优先发送");}
}

这时候假如要新增其他紧急程度那直接再建一个类就好了,非常方便。

6、最后新建一个测试类来测试一下:

package com.zwx.design.pattern.bridge;import java.io.IOException;public class TestBridge {public static void main(String[] args) throws IOException {IMessage iMessage = new EmailMessage();AbstractMessage abstractMessage = new UrgentMessage(iMessage);//紧急邮件消息abstractMessage.sendMessage("您好","张三丰");//再来一个普通邮件消息System.out.println("------------分割线---------------");abstractMessage = new CommonMsg(iMessage);abstractMessage.sendMessage("您好","郭靖");}
}

输出结果如下:

这是紧急消息,请优先发送
邮件消息->张三丰:您好
------------分割线---------------
这只是一个普通消息
邮件消息->郭靖:您好

桥接模式优缺点

优点:
1、分离了抽象部分及其实现部分两个维度,实现了代码的解耦,提高了系统的扩展性。
3、扩展功能时只需要新增类,无需修改源代码,符合开闭原则。
4、通过组合而不是继承来实现耦合,符合合成复用原则。

缺点:
1、增加了系统的理解难度和设计难度(这也算是大部分设计模式的共性)
2、需要正确识别系统中各个独立变化的维度
总结

本文主要介绍桥接模式的原理,并结合了示例对其进行了分析。桥接模式也是通过组合来实现的。我们在开发中大家都知道要解耦,解耦的实质就是减少对象之间的关联,而继承是一种强关联,因为一旦通过继承,那么子类就会拥有父类所有公开的方法和属性,有些可能并不是子类需要的,而组合就不一样,组合是一种弱关联,我只是持有一个对象,但是我持有对象所拥有的功能并不是我的,和我并没有很强烈的关系。所以实质上在很多场景我们都可以通过组合来解耦继承对象之间的强关联关系。

最后还是希望大家记住编程中的一条原则,那就是:多用组合,少用继承。

适配器模式与桥接模式相关推荐

  1. Java设计模式(四):结构性模式(适配器模式、桥接模式、装饰模式、组合模式、外观模式、亨元模式、代理模式)

    目录 一· 适配器设计模式 1.1 现实生活中的适配器例子 1.2 基本介绍 1.3 工作原理 1.4 类适配器模式 1.5 对象适配器模式 1.6 接口适配器模式 1.7 适配器模式在 Spring ...

  2. 图解Java设计模式学习笔记——结构型模式(适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式、代理模式)

    一.适配器模式(类适配器.对象适配器.接口适配器) 1.现实生活中的例子 泰国插座用的是两孔的(欧标),可以买个多功能转换插头(适配器),这样就可以使用了国内的电器了. 2.基本介绍 适配器模式(Ad ...

  3. 设计模式之结构型模式:适配器模式、桥接模式、组合模式、装饰器模式、代理模式、

    文章目录 什么是结构型模式 适配模式 适配器的数据结构 适配器的实现 缺省适配器 适配器优缺点 适配器模式的使用环境 桥接模式 桥接模式数据结构 桥接模式的实现 桥接模式和适配器模式的联用 桥接模式的 ...

  4. 处理多维度变化——桥接模式

    本文转载自 :http://blog.csdn.net/lovelion/article/details/7464183 在正式介绍桥接模式之前,我先跟大家谈谈两种常见文具的区别,它们是毛笔和蜡笔.假 ...

  5. android 桥梁模式,【设计模式】桥接模式

    本文主要介绍:桥接模式概念和用法. 模式背景 生活中,我们如果一个笔有三种型号:大,中,小.颜色一共有M种.如果需要所有型号都有相对应的颜色,那么就需要3*M只笔.但是如果我们转换一下:M种颜色代表M ...

  6. 设计模式(9)[JS版]-JavaScript设计模式之如何实现桥接模式???

    目录 1 什么是桥接模式 2 参与者 3 实例讲解 4 总结 1 什么是桥接模式 Bridge模式允许两个组件,即客户端和服务一起工作,每个组件都有自己的接口.Bridge是一种高级架构模式,它的主要 ...

  7. 设计模式(16):结构型-桥接模式(Bridge)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

  8. 【Java设计模式】桥接模式

    ✍ 在介绍桥接模式之前,我们引入一个场景: 设想如果要绘制矩形.圆形.椭圆.正方形,我们至少需要4 个形状类,但是如果绘制的图形需要具有不同的颜色,如红色.绿色.蓝色等,此时至少有如下两种设计方案: ...

  9. 设计模式学习笔记(十五)-桥接模式

    处理多维度变化 在正式介绍桥接模式之前,我先跟大家谈谈两种常见文具的区别,它们是毛笔和蜡笔.假如我们需要大中小3种型号的画笔,能够绘制12种不同的颜色,如果使用蜡笔,需要准备3×12 = 36支,但如 ...

最新文章

  1. JVM运行时数据区---方法区(前言)
  2. 在linux下python爬虫进程发生异常时自动重启直至正常结束的方法
  3. 末端物流 | 快递驿站的产品逻辑
  4. Asp.Net生命周期系列三
  5. 月均数据_利用Python进行数据分析(附详细案例)
  6. 坑了我一个小时的脚本执行
  7. sqlite3数据库-常用命令
  8. 【Other】千字文 硬笔 楷书 字帖
  9. [dlang](一)利用dub搭建vibe.d,hibernated,mysql开发环境
  10. 使用两个路由器级连实现共用一个宽带
  11. P01914100尹自杨
  12. 程序员学历不好是硬伤?苹果公司 50% 员工没大学学历
  13. 将React Native 集成进现有OC项目中(过程记录) 、jsCodeLocation 生成方式总结
  14. JS生成唯一id方式介绍(UUID和NanoID)
  15. 超级产品:解秘国潮对服装类企业的柔性供应链改造
  16. mysql 在linux环境下导出,window下导入报ASCII '\0' appeared in the statement
  17. linux fstab 远程,linux限制root用户远程ssh登录的...-linux下ssh无密码登录的配置方...-linux下修复fstab文件的方法_169IT.COM...
  18. cesium 自定义百度底图
  19. adobe pdf 启用下划线快捷键
  20. 基础计算机指令,计算机科学基础_2 - CPU,指令

热门文章

  1. 工作流引擎设计之子流程功能实现
  2. 假设函数、损失函数、 成本函数
  3. 如何鉴别IBM T40成色
  4. C语言使用结构体存储学生成绩信息
  5. JSP指令是什么?JSP包含哪些指令?
  6. Python模块卸载
  7. IT中的DEV SIT UAT PET SIM PRD 都是什么意思?
  8. AP计算机A自学笔记:Comparable接口
  9. [Mugeda HTML5技术教程之14]案例分析:制作网页游戏
  10. 投资22亿元!迈瑞医疗深圳龙华基地开工,打造集团全球供应链总部 | 美通社头条...