适配器模式
来源:互联网 发布:淘宝怎么用微信支付吗 编辑:程序博客网 时间: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! 姚明 进攻!
好,这时姚明也可以正常参与到训练了。
最后,我们看下整个训练计划的类图:
最后,依然要说明的是:适配器很像“亡羊补牢”,如何可以在早期就定义好,就不存在适配的问题了。
- 适配器及适配器模式
- 适配器及适配器模式
- 适配器模式(类适配器)
- 适配器模式(默认适配器)
- 适配器模式(对象适配器)
- 适配器模式-类适配器
- 适配器模式-对象适配器
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- 适配器模式
- GridView+下拉刷新+上拉加载
- [随笔]示波器"触发",爱它无法自拔
- 第八周项目四(1)-游戏中角色类的增强版
- bzoj 1119: [POI2009]SLO(置换)
- Android正则
- 适配器模式
- HDU 5249 KPI STL
- BSG白山极客挑战赛——数数字(递推)
- leetcode #16 in cpp
- 洛谷 P1352 TYVJ P1052 CODEVS 1380 没有上司的舞会
- 斗地主
- flask搭建个人博客(三)——后端视图函数
- 拿到阿里,网易游戏,腾讯,smartx的offer的过程
- codevs1380 没有上司的舞会