您的位置:首页 > 其它

适配器模式

2016-05-21 10:22 507 查看
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工

作,就是适配器模式

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

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

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

适配器的类图:



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

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 stub
this.name = name;
}

@Override
public void attack() {
// TODO Auto-generated method stub
System.out.println(name + " Attack!");
}

@Override
public void defense() {
// TODO Auto-generated method stub
System.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 stub
this.name = name;
}

@Override
public void attack() {
// TODO Auto-generated method stub
System.out.println(name + " Attack!");
}

@Override
public void defense() {
// TODO Auto-generated method stub
System.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 stub
this.name = name;
}

@Override
public void attack() {
// TODO Auto-generated method stub
System.out.println(name + " Attack!");
}

@Override
public void defense() {
// TODO Auto-generated method stub
System.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;
}

@Override
public void 进攻() {
// TODO Auto-generated method stub
System.out.println(name + " 进攻!");
}

@Override
public void 防守() {
// TODO Auto-generated method stub
System.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);
}

@Override
public void attack() {
// TODO Auto-generated method stub
foreign.进攻();
}

@Override
public void defense() {
// TODO Auto-generated method stub
foreign.防守();
}

}


最后我们再修改下教练类

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!    姚明 进攻!


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

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



最后,依然要说明的是:适配器很像“亡羊补牢”,如何可以在早期就定义好,就不存在适配的问题了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: