适配器模式

来源:互联网 发布:淘宝怎么用微信支付吗 编辑:程序博客网 时间:2024/04/29 05:56

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工

作,就是适配器模式


它主要能解决的应用场景是在:系统的数据和行为都正确,但是接口不符合时,且双方都不方便修改自己对外接

口时,这是就可以采用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望

复用一些现存的类,但是接口却又与复用环境要求不一致的情况。比如:需要复用早期其他项目的一些功能。


适配器的类图:


上图中,我们可以分析出模式中的角色有:


1、目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。

2、需要适配的类(Adaptee):需要适配的类或适配者类。

3、适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。


而Client类最终面对的是 Target 接口(或抽象类),它只能够使用符合这一目标标准的子类。


使用适配器模式的优势在于:


1、通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。简单、直接、紧凑。

2、复用了现存的类,解决了现存类和复用环境要求不一致的问题。

3、将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。

4、一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和

它的子类都适配到目标接口。


但是适配器模式也有其缺陷,如果早期双发就统一了接口,就不会有适配器模式的存在了,当然针对不同的厂商,接

口不一致,这是使用适配器就很合适。很多人分不清代理模式与适配器模式有合不同,确实粗略的看起来,都是提供

一个对外的接口, 隐藏真实的自己。但是细分下来,还是能区分,一个重在代理,行为方法都必须要一模一样。而适

配却不是,它重在适配,是要求按照客户的要求去适配,它的行为方法需要要客户要求保持一致。


如下示例:

我这里也采用《大话设计模式》中的例子,很有趣。它这个例子有3种角色的存在:分别是教练(客服端),

教员(如:巴蒂尔,麦迪, 姚明等,但是姚明来自中国,听不明白英文 ,需要适配),翻译(适配者)


我们先来设计一个球员抽象类,行为提供:进攻,防守


package com.my.adapter.player;/** * 定义一个球员抽象接口 *  * @author Administrator * */public interface IPlayer {/** * 定义一个进攻方法 */public void attack();/** * 定义一个防守方法 */public void defense();}



再分别定义3个子类,分别是:前锋,中锋,后卫  实现上述接口

package com.my.adapter.player;/** * 定义一个前锋类,实现Player接口 *  * @author Administrator * */public class ForwardsPlayer implements IPlayer {private String name;public ForwardsPlayer() {super();// TODO Auto-generated constructor stub}public ForwardsPlayer(String name) {// TODO Auto-generated constructor stubthis.name = name;}@Overridepublic void attack() {// TODO Auto-generated method stubSystem.out.println(name + " Attack!");}@Overridepublic void defense() {// TODO Auto-generated method stubSystem.out.println(name + " Defense!");}}


package com.my.adapter.player;/** * 定义一个中锋类,实现Player接口 *  * @author Administrator * */public class CenterPlayer implements IPlayer {private String name;public CenterPlayer() {super();// TODO Auto-generated constructor stub}public CenterPlayer(String name) {// TODO Auto-generated constructor stubthis.name = name;}@Overridepublic void attack() {// TODO Auto-generated method stubSystem.out.println(name + " Attack!");}@Overridepublic void defense() {// TODO Auto-generated method stubSystem.out.println(name + " Defense!");}}


package com.my.adapter.player;/** * 定义一个后卫类,实现Player接口 *  * @author Administrator * */public class GuardsPlayer implements IPlayer {private String name;public GuardsPlayer() {super();// TODO Auto-generated constructor stub}public GuardsPlayer(String name) {// TODO Auto-generated constructor stubthis.name = name;}@Overridepublic void attack() {// TODO Auto-generated method stubSystem.out.println(name + " Attack!");}@Overridepublic void defense() {// TODO Auto-generated method stubSystem.out.println(name + " Defense!");}}


再定义一个教练类,用于训练,发出指令

package com.my.adapter.client;import com.my.adapter.player.CenterPlayer;import com.my.adapter.player.ForwardsPlayer;import com.my.adapter.player.GuardsPlayer;import com.my.adapter.player.IPlayer;public class Trainer {public static void main(String[] args) {// 训练队员IPlayer forward = new ForwardsPlayer("巴蒂尔");forward.attack();IPlayer guard = new GuardsPlayer("麦迪");guard.defense();IPlayer center = new CenterPlayer("姚明");center.attack();}}



得到的结果是:

巴蒂尔 Attack!   麦迪 Defense!    姚明 Attack!


对于巴蒂尔,麦迪而言,教练的指令很容易就接收到了,但是姚明,来自中国,却无法理解Attack代表什么意思,导致他一头雾水的战在原地不知道干啥,这是我们的翻译就来了。


我们先定义一个外籍球类,用于他们本国训练

package com.my.adapter.foreign;/** * 定义一套外籍球员训练行为类 *  * @author Administrator * */public interface IForeignPlayer {public void 进攻();public void 防守();}


package com.my.adapter.foreign;/** * 定义一个外籍球员类 *  * @author Administrator * */public class ForeignPlayer implements IForeignPlayer {private String name;public ForeignPlayer() {super();// TODO Auto-generated constructor stub}public ForeignPlayer(String name) {this.name = name;}@Overridepublic void 进攻() {// TODO Auto-generated method stubSystem.out.println(name + " 进攻!");}@Overridepublic void 防守() {// TODO Auto-generated method stubSystem.out.println(name + " 防守!");}}




然后再给这个外籍球员类,添加一个翻译,适配器类

package com.my.adapter.adapter;import com.my.adapter.foreign.ForeignPlayer;import com.my.adapter.foreign.IForeignPlayer;import com.my.adapter.player.IPlayer;/** * 翻译类(适配类) *  * @author Administrator * */public class AdapterPlayer implements IPlayer {// 声明外籍球员类private IForeignPlayer foreign = null;public AdapterPlayer() {super();// TODO Auto-generated constructor stub}public AdapterPlayer(String name) {super();foreign = new ForeignPlayer(name);}@Overridepublic void attack() {// TODO Auto-generated method stubforeign.进攻();}@Overridepublic void defense() {// TODO Auto-generated method stubforeign.防守();}}



最后我们再修改下教练类

package com.my.adapter.client;import com.my.adapter.adapter.AdapterPlayer;import com.my.adapter.player.CenterPlayer;import com.my.adapter.player.ForwardsPlayer;import com.my.adapter.player.GuardsPlayer;import com.my.adapter.player.IPlayer;public class Trainer {public static void main(String[] args) {// 训练队员IPlayer forward = new ForwardsPlayer("巴蒂尔");forward.attack();IPlayer guard = new GuardsPlayer("麦迪");guard.defense();// IPlayer center = new CenterPlayer("姚明");// center.attack();IPlayer center = new AdapterPlayer("姚明");center.attack();}}



这时运行的结果就是:

巴蒂尔 Attack!    麦迪 Defense!    姚明 进攻!


好,这时姚明也可以正常参与到训练了。


最后,我们看下整个训练计划的类图:


最后,依然要说明的是:适配器很像“亡羊补牢”,如何可以在早期就定义好,就不存在适配的问题了。

0 0
原创粉丝点击