定义:“转换接口”
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
我理解的“一个类的接口”是被适配对象Adapteede 接口,“客户希望的另外一个接口”就是客户端已经的接口,因为客户端只能适应这一种接口,所以它期望这个接口
实现目标:就是客户端Client希望通过这个原有的Target接口,实现被适配对象的新功能
模式中的角色:
目标接口(Target):客户所期待的接口,就是客户现在有的接口,旧接口。目标可以是具体的或抽象的类,也可以是接口。
需要适配的类(Adaptee):需要适配的类或适配者类,就是需要的接口,需要用旧接口实现新功能的新接口。
适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。
UML图:
Target.java
/**
*
*/
package com.hust.adapter1;
/**
* @author tuke
*
*/
public interface Target {
public void Request();
}
NowConcreteTarget.java
/**
*
*/
package com.hust.adapter1;
/**
* @author tuke
*
*/
public class NowConcreteTarget implements Target {
public void Request() {
System.out.println("这是一个现有的具体类,与客户端相适应的接口,只具有普通功能");
}
}
Adaptee.java
/**
*
*/
package com.hust.adapter1;
/**
* @author Administrator
* 已存在的、具有特殊功能、但不符合我们既有的标准接口的类,被适配的类就是客户端要通过现有的接口(Target的Request方法)获得这个被适配的方法SpecificRequest
*/
public class Adaptee {
public void SpecificRequest(){
System.out.println("被适配的类,有特殊功能");
}
}
Adapter.java
/**
*
*/
package com.hust.adapter1;
/**
* @author tuke
* 适配器类,直接关联被适配类,同时实现标准接口
*/
public class Adapter implements Target {//实现现有接口,即标准接口,旧接口,现有接口
private Adaptee mAdaptee;//被适配类的对象做成员变量,就是组合不适合现有接口的类的对象
public Adapter(Adaptee mAdaptee) {
this.mAdaptee = mAdaptee;
}
public void Request() { // Request是客户端期待的接口,即是现有接口,旧接口,因为就现在来看,客户端只能适应这种接口
mAdaptee.SpecificRequest(); //SpecificRequest这是新的接口,不适合客户端的接口,所以要适配,客户端通过现有接口Request就能实现新的功能
}
}
自己实践了一个别人的栗子,很好的栗子。
我们国家的电器使用普通的扁平两项或三项插头,而去外国的话,使用的标准就不一样了,比如德国,使用的是德国标准,是两项圆头的插头。如果去德国旅游,那么我们使用的手机充电器插头无法插到德国的插排中去,那就意味着我们无法给手机充电。怎样解决这个问题呢?只要使用一个电源转化器就行了。
该适配器下面的插头符合德国标准,可以插到德国的插排中去,上面提供的接口符合国标,可以供我们的手机充电器使用。
实现电源适配器:
1,代码中有两个接口,分别为德标接口和国标接口,分别命名为DBSocketInterface和GBSocketInterface,
2.此外还有两个实现类,分别为德国插座和中国插座,分别为DBSocket和GBSocket。
3,为了提供两套接口之间的适配,我们提供了一个适配器,叫做SocketAdapter。
4,除此之外,还有一个客户端,比如是我们去德国旅游时住的一家宾馆,叫Hotel,在这个德国旅馆中使用德国接口
德国接口:DBSocketInterface.java
package com.hust.adapter2;
/**
* 德标接口
*/
public interface DBSocketInterface {
/**
* 这个方法的名字叫做:使用两项圆头的插口供电
*
*/
void powerWithTwoRound();
}
DBSocket.java
package com.hust.adapter2;
/**
* 德国插座
*/
public class DBSocket implements DBSocketInterface{
public void powerWithTwoRound(){
System.out.println("使用两项圆头的插孔供电");
}
}
德国旅馆是一个客户端,它里面有德标的接口,可以使用这个德标接口给手机充电:
package com.hust.adapter2;
public class Hotel {
//旅馆中有一个德标的插口接口
private DBSocketInterface dbSocket;
public Hotel(){}
public Hotel(DBSocketInterface dbSocket) {
this.dbSocket = dbSocket;
}
public void setSocket (DBSocketInterface dbSocket){
this.dbSocket = dbSocket;
}
//旅馆中有一个充电的功能
public void charge(){
//使用德标插口充电
dbSocket.powerWithTwoRound();
}
}
现在写一段代码进行测试:
package com.hust.adapter2;
public class Test {
public static void main(String[] args) {
//初始化一个德国插座对象, 用一个德标接口引用它
DBSocketInterface dbSoket = new DBSocket();
//创建一个旅馆对象
Hotel hotel = new Hotel(dbSoket);
//在旅馆中给手机充电
hotel.charge();
}
}
输出:使用两项圆头的插孔供电
现在我去德国旅游,带去的三项扁头的手机充电器。如果没有带电源适配器,我是不能充电的,因为不可能为了我一个旅客而为我更改墙上的插座,更不可能为我专门盖一座使用中国国标插座的宾馆。
因为人家德国人一直这么使用,并且用的挺好,俗话说入乡随俗,我就要自己想办法来解决问题。对应到我们的代码中,也就是说,上面的Hotel类,DBSocket类,DBSocketInterface接口都是不可变的(由德国的客户提供),如果我想使用这一套API,那么只能自己写代码解决。
GBSocketInterface.java
package com.hust.adapter2;
/*
* 国标接口
* */
public interface GBSocketInterface {
/**
* 这个方法的名字叫做:使用三项扁头的插口供电
*/
void powerWithThreeFlat();
}
GBSocket.java
package com.hust.adapter2;
/**
* 中国插座
*/
public class GBSocket implements GBSocketInterface{
public void powerWithThreeFlat() {
System.out.println("使用三项扁头插孔供电");
}
}
可以认为这两个东西是我带到德国去的,目前他们还不能使用,因为接口不一样。那么我必须创建一个适配器,这个适配器必须满足以下条件:
1 ,必须符合德国标准的接口,否则的话还是没办法插到德国插座中;
2 ,在调用上面实现的德标接口进行充电时,提供一种机制,将这个调用转到对国标接口的调用 。
这就要求:
1 ,适配器必须实现原有的旧的接口
2, 适配器对象中持有对新接口的引用,当调用旧接口时,将这个调用委托给实现新接口的对象来处理,也就是在适配器对象中组合一个新接口。
SocketAdapter.java
package com.hust.adapter2;
/*
* 插座适配器
* */
public class SocketAdapter implements DBSocketInterface{ //实现旧接口,现有接口
private GBSocketInterface gbSocket;//组合新接口,不适合现有接口的类,需要被适配的类
/**
* 在创建适配器对象时,必须传入一个新街口的实现类
* @param gbSocket
*/
public SocketAdapter(GBSocketInterface gbSocket) {
this.gbSocket = gbSocket;
}
/**
* 将对就接口的调用适配到新接口
*/
public void powerWithTwoRound() {
gbSocket.powerWithThreeFlat();
}
}
下面写一段测试代码来验证一下适配器能不能工作,我们按步骤一步步的写出代码,以清楚的说明适配器是如何使用的。
1 我去德国旅游,带去的充电器是国标的(可以将这里的GBSocket看成是充电器)
//国标插座适配器
GBSocketInterface gbSocket = new GBSocket();
2 来到德国后, 找到一家德国宾馆住下 (这个宾馆还是上面代码中的宾馆,使用的依然是德国标准的插口)
//客户端
Hotel hotel = new Hotel();
3 由于没法充电,我拿出随身带去的适配器,并且将我带来的充电器插在适配器的上端插孔中。这个上端插孔是符合国标的,我的充电器完全可以插进去。
//插座适配器
SocketAdapter socketAdapter = new SocketAdapter(gbSocket);
4 再将适配器的下端插入宾馆里的插座上
//客户端设置适配器
hotel.setSocket(socketAdapter);
5 可以在宾馆中使用适配器进行充电了
//调用客户端的原有接口,但是有了适配器,适配了不合适的类,使用的是同一个方法就有了新功能
hotel.charge();
这个栗子对理解适配器模式很好,贴近生活。
TestAdapter.java
package com.hust.adapter2;
public class TestAdapter {
public static void main(String[] args) {
//国标插座适配器
GBSocketInterface gbSocket = new GBSocket();
//客户端
Hotel hotel = new Hotel();
//插座适配器
SocketAdapter socketAdapter = new SocketAdapter(gbSocket);
//客户端设置适配器
hotel.setSocket(socketAdapter);
//调用客户端的原有接口,但是有了适配器,适配了不合适的类,使用的是同一个方法就有了新功能
hotel.charge();
}
}
参考:http://www.2cto.com/kf/201401/275535.html