周末窝在家里面打王者荣耀,女友在旁边玩个人电脑,我嫌她播放的综艺节目声音比较大,因而建议她戴耳机。设计模式
Adapter Pattern,一般被翻译成适配器模式,有时候也叫作包装模式(wrapper pattern),是GOF 23种设计模式之一。主要做用是将一个类的接口转换成客户但愿的另一个接口。适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。bash
《Design Patterns: Elements of Reusable Object-Oriented Software》(《设计模式》),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。这几位做者常被称为"Gang of Four),简称GOF。app
GOF中将适配器模式分为类适配器模式和对象适配器模式。框架
对象适配器模式iphone
在这种适配器模式中,适配器容纳一个它包裹的类的实例。在这种状况下,适配器调用被包裹对象的物理实体。ide
类适配器模式学习
这种适配器模式下,适配器继承自已实现的类(通常多重继承)。ui
两者区别仅在于适配器角色对于被适配角色的适配是经过继承仍是组合来实现的,因为Java中不支持多继承,并且类适配器模式有破坏封装之嫌,并且咱们也提倡多用组合少用继承。因此本文主要介绍对象适配器。this
咱们生活中常常须要用到插口转换器,好比如今不少手机都只有一个插口,这个口能够直接用来充电和听音乐。可是前提是咱们使用的充电器和耳机的插口要和这个设备适配的。spa
目前市面上不少手机的插口都是type-c或者Lightning型号:
可是,咱们经常使用的耳机型号倒是2.5mm和3.5mm的圆形接口:
一、系统须要使用现有的类,而此类的接口不符合系统的须要。
二、想要创建一个能够重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在未来引进的类一块儿工做,这些源类不必定有一致的接口。
三、经过接口转换,将一个类插入另外一个类系中。(好比老虎和飞禽,如今多了一个飞虎,在不增长实体的需求下,增长一个适配器,在里面包容一个虎对象,实现飞的接口。)
适配器模式,就能够解决以上的问题。
下面咱们就使用适配器模式,模拟一种场景:使用一个安卓的type-c充电器给只支持 Lightning接口的苹果手机充电(假设能够完美支持)。
已知,咱们有一个type-c充电器、一个Lightning插口的苹果手机。不管是type-c仍是Lightning,都是一种标准,在代码中,标准即接口。因此咱们先定义两个接口:
/**
* Lightning充电接口
*/
public interface LightningInterface {
public void chargeWithLightning();
}
/**
* TypeC充电接口
*/
public interface TypeCInterface {
public void chargeWithTypeC();
}复制代码
接下来定义咱们的苹果手机,他只支持使用 Lightning插口充电:
public class IphoneX {
private LightningInterface lightningInterface;
public IphoneX() {
}
public IphoneX(LightningInterface lightningInterface) {
this.lightningInterface = lightningInterface;
}
public void charge() {
System.out.println("开始给个人IphoneX手机充电...");
lightningInterface.chargeWithLightning();
System.out.println("结束给个人IphoneX手机充电...");
}
//setter/getter
}复制代码
而后再来看看咱们的安卓充电器应该如何定义:
/**
* 安卓设备的充电器
*/
public class AndroidCharger implements TypeCInterface {
@Override
public void chargeWithTypeC() {
System.out.println("使用Type-C型号的充电器充电...");
}
}复制代码
有了安卓充电器和苹果手机。接下来,咱们就要定义一个适配器了,但愿经过这个适配器,咱们能够实现使用安卓设备的充电器给苹果手机充电:
public class Adapter implements LightningInterface {
private TypeCInterface typeCInterface;
public Adapter() {
}
public Adapter(TypeCInterface typeCInterface) {
typeCInterface = typeCInterface;
}
@Override
public void chargeWithLightning() {
typeCInterface.chargeWithTypeC();
}
//setter/getter
}复制代码
这个适配器实现了LightningInterface,并组合了TypeCInterface,当外部调用chargeWithLightning方法的时候,实际上调用的是typeCInterface.chargeWithTypeC方法。
就像电源适配器,他实现的是一个Lightning的规范,自身是一个Lightning的插头,但实际充电的时候,他是经过typc-c的电源进行的,他起到的是一个中间转换的做用。
接着咱们定义客户端,实现咱们想要的充电功能:
public class Main {
public static void main(String[] args) {
Adapter adapter = new Adapter(new AndroidCharger());
IphoneX iphoneX = new IphoneX();
iphoneX.setLightningInterface(adapter);
iphoneX.charge();
}
}复制代码
输出结果以下:
开始给个人IphoneX手机充电...
使用Type-C型号的充电器充电...
结束给个人IphoneX手机充电...复制代码
上面的例子经过适配器,咱们使用一个安卓的type-c充电器给一个只支持Lightning接口的苹果手机充电。
上面的代码,就是一个适配器模式的例子,这个例子中,共出现了四种角色:
优势
适配器模式(对象适配器模式),是一种组合优于集成的思想的实现。经过使用适配器模式,咱们能够最大程度的复用已有的了类和代码。他主要有如下有点:
将目标类和适配者类解耦,经过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
增长了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来讲是透明的,并且提升了适配者的复用性。
灵活性和扩展性都很是好,经过使用配置文件,能够很方便地更换适配器,也能够在不修改原有代码的基础上增长新的适配器类,彻底符合“开闭原则”。
缺点
固然,适配器模式并非完美的,过分使用仍是会带来一些问题的。缺点以下:
过多地使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统若是太多出现这种状况,无异于一场灾难。所以若是不是颇有必要,能够不使用适配器,而是直接对系统进行重构。
关于适配器模式的使用场景,通常主要是当咱们须要修改一些正在运行着的代码,而且但愿能够复用原有代码实现新的功能的时候,就要考虑适配器模式。
在Spring框架中,就大量的使用了适配器模式,读者能够打开本身的IDE,尝试着以关键字"Adapter"全局搜索下,必定会有不少的实际应用。
当你遇到的问题,和你想用安卓充电器给苹果手机充电相似的时候,就必定要想到适配器模式哦!
这是关于设计模式的第三篇,前两篇分别是:《漫话:如何给女友解释什么是策略模式?》《漫话:如何给女友解释什么是单例模式?》还想学习哪一种设计模式,欢迎留言哦。