浅谈设计模式 – 适配器模式(八)
前言:
适配器模式大略是零碎用的最多的模式,在 spring
框架当中能够看到他的各种利用,比方咱们想要注册本人的拦截器,或者须要沿用旧接口实现一些本人的实现,都能够应用适配器模式进行实现,适配器模式是一种十分贴合 起码常识准则 的设计模式,这篇文章将会具体介绍一下适配器模式。
文章目标:
- 理解什么是适配器模式
- 适配器模式的优缺点
- 实战,理解适配器模式
什么是适配器模式?
定义:在不改变客户代码的状况下实现一个接口向另一个接口的自在转化,让本来不能适配的接口具备类似的性能。
适配器存在三个角色,客户端,适配器,被适配者。适配器实现目标的接口,并且持有被适配者的实例
适配器模式是一种:行为型模式。因为他将一个接口的行为转化为另一个接口的行为。
适配器模式优缺点:
先说说适配器模式的长处:
- 能够让客户从接口的实现当中解放
- 让客户由本来的面向实现转变为面向接口
- 让被适配对象具备接口性能的同时能够实现自在的扩大
上面说说毛病,其实适配器的毛病也比拟显著:
- 因为 JAVA 不反对多继承,无奈实现多个对象的适配工作,只能应用多接口的模式适配,实现起来要比其余的语言略微简单一些。
- 适配器最难改变的中央在于适配指标的办法,假如适配指标的办法组合了多个被适配对象,此时改变任意一个被适配对象,都会对适配的办法带来影响,同时适配办法也是最难以改变的。
对于适配器应用的倡议:
- 一个适配器最好做一个类的适配工作。
- 如果一个适配器须要适配多个类,须要思考是否存在关联性
- 能够应用双向接口适配器,既能够实现旧接口的办法不改变,同时实现新接口的新实现。要做到这一步,要害是确保:两个接口
应用继承还是应用组合
对于适配这一个概念,咱们能够应用两种模式:继承 和 组合
首先说下继承,继承是指对于一个类进行“超类”的扩大,如果此时咱们应用继承的模式去扩大指标对象,尽管从实践上能够实现一个适配器间接具备两个对象的性能,然而因为 JAVA 自身是不反对多继承的,同时 多用组合,少用继承 是软件设计行业一条十分推崇的定律。所以继承的模式“不太敌对”。
再说下应用组合的模式,组合是比拟推崇的模式,咱们在实现目标接口的根底之上,组合被适配的对象,让旧接口的性能能够兼容新接口的实现。这也是 JAVA 代码当中常常会见到的一种模式,同时在框架中以相似“套版”的模式呈现。
适配器模式的特点:
适配器的实现就是把客户类的申请转化为对适配者的相应接口的调用 ,当客户端进行申请的时候,指标对象通过适配器,将申请的逻辑转变为“适宜”被适配对象的申请,由适配器实现这一转化细节,适配过后执行被适配对象的性能,这种转化对于客户端来说是荫蔽的,同时会让客户端误认为是指标对象实现的了工作,所以这种模式的最大特点是: 申请代码能够齐全不须要扭转。
适配器模式了解
上面依据适配器模式,介绍一下集体对于适配器模式的一些了解。
从插头引申适配器模式
插头有很多中标准,然而日常生活罕用的插头个别是两孔或者三孔的插头,个别状况下一个新厂商的插头须要兼容旧厂商生产的插头,同时须要兼容旧厂商的办法,不想扭转旧厂商的实现状况下,须要实现新厂商的实现,这时候通常须要依赖一个适配器去做适配,适配器如同一个两头通信人,能够将看起来毫不相干的两个对象之间产生肯定的关联个性。
单向适配和双向适配
须要留神的是适配器模式肯定不要教条的认为只能单向的适配,适配器是能够进行双向适配的,然而此时咱们通常须要 两个接口 来实现双向的适配。
适配器模式和起码常识准则
适配器模式对应的一个软件设计准则是:起码常识准则
起码常识准则:接口负责尽可能少的性能。用文言来讲就是 简洁
遵循起码常识准则
对于任何对象,在他的办法内他应该做这些事件
- 只操作对象本人自身
- 传递的对象参数或者和该对象返回的后果对象(然而会有依赖传递的问题)
- 办法自身创立的对象
- 对象的任何组件:HAS-A(组合)的外部对象
这里须要小心依赖磁铁,也就是依赖了依赖对象的对象,简略了解就是应用了其余对象返回的另一个对象,这种状况很容易被忽视,而且通常状况下是 不会呈现问题 的,然而一旦要进行重构,这种代码就很容易造成逻辑凌乱。
适配器的调用流程
- 客户端通过指标接口调用适配器的办法发送对应的申请。
- 适配器用适配办法转化为一个或者多个被适配器的多种办法
- 客户端失去的接口会误以为是指标对象在工作。同时不须要进行任何变动就能够实现新的性能或者办法。
适配器模式的结构图
上面是适配器模式的结构图:
+ client 客户端
+ Target 指标接口,+ Adapter 适配器,负责将两个对象进行关联,产生类似的业务
+ Appropriate object 被适配对象, 代表了须要适配的对象内容
下面的结构图展现了如何指标接口转化为被适配对象的行为。
实战
说了不少的实践内容,上面咱们依据一个模仿场景制订一份适配器的代码:
模仿场景
在任天堂发售的 switch
在日版和港版的两个版本当中,充电充电器的设计是不一样的,因为港版沿用了英国应用的是三插式(大部分电器都是这种状况),而我国应用的是较为通用二插式,日本在设计的时候也是应用二插式,所以在充电器的设计下,日本不须要进行适配,间接能够插到我国的插座上,而港版通常须要购买转接头或者买其余的适配器。
不应用设计模式
笔者在构思这一块没有思考好不应用设计模式如何实现,其实这种状况下,不应用设计模式最好方法通常就是找一个第三方工具进行代替,比方咱们能够买一个 switch 的充电宝,每次充电只有充充电宝就行了,连充电器都省了 ……
应用设计模式
还是间接从设计模式开干把,很显然,既然港版都是用的转接头,那么咱们的代码就应用转接头来实现这一块的性能:
上面是依据模仿场景进行剖析,咱们按照适配器的结构设计出根本对象:
- switch:咱们权且把它设想是客户端,咱们把它设想成一个想要充电的“人”。发动了充电这一个申请来匹配适合的充电器
- JapanMouth:日版充电器,间接对标国内的插口
- Mouth:插口接口。
- EngMouth:英式插口,依照英国的规范设计的插口。
- Adapter:适配器,在这里充当的是转接器,负责转接插口
有了下面这些定义,上面依据具体的设计出代码:
public class Switch {
private TwoHoleCharge twoHoleCharge;
public Switch(TwoHoleCharge twoHoleCharge) {this.twoHoleCharge = twoHoleCharge;}
/**
* 模仿充电办法
*/
public void recharge(){twoHoleCharge.jack();
}
public TwoHoleCharge getTwoHoleCharge() {return twoHoleCharge;}
public void setTwoHoleCharge(TwoHoleCharge twoHoleCharge) {this.twoHoleCharge = twoHoleCharge;}
}
// 插口接口
public interface Mouth {void jack();
}
public class JapanMouth implements Mouth {public void jack(){System.out.println("日版:开始充电");
}
}
public class EngMouth {public void specialJack(){System.out.println("港版:开始充电");
}
}
//== 要害 == 适配器
public class Adapter implements Mouth {
private EngMouth engMouth;
public Adapter(EngMouth engMouth) {this.engMouth = engMouth;}
@Override
public void jack() {engMouth.specialJack();
}
}
public class Main {public static void main(String[] args) {
// 日版插口能够间接应用
Mouth mouth = new JapanCharge();
Switch aSwitch = new Switch(mouth);
aSwitch.recharge();
// 港版插口须要转接口
Mouth mouth2 = new Adapter(new EngMouth());
aSwitch.setMouth(mouth2);
aSwitch.recharge();}/* 运行后果:日版:开始充电
港版:开始充电
*/
}
代码比较简单,应该比拟好了解,这里重点关注一下 Adapter
的适配器对象,通过组合的模式,将被适配对象“暗藏”到了指标对象的办法外部,实现了接口的适配,客户在应用的时候,只须要用一个适配器就能够让港版能够间接兼容到国内的电网。
当然,在现实生活中应用适配器其实比拟麻烦,因为总要多带点货色,比方我集体就比拟恶感当初的手机都把耳机孔给削掉了,出门用个有线听歌还得买个转接口 ……
总结案例
适配器的案例生存中还是非常常见的,能够举出许许多多的场景进去,同时不须要思考过多的其余因素,适配器十分贴合“凋谢 - 敞开”的准则,对于批改进行了凋谢,对于原有的代码没有进行批改,然开发人员只须要关注如何适配,而不须要太关怀原来的实现,
总结
适配器模式是一个重点模式,他能够实现在不改变旧代码的根底上对于一个指标对象进行二次扩大和降级,并且只须要付出很小的代价就能够实现很多自定义的操作,总体上来说,适配器的弊病在理论的编码过程中往往被规范化的设计而弱化,当然,更多的应用场景可能还是在框架当中,因为框架中应用适配器是一种很常见的行为。