适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
适配器模式的好处是,客户不必为了应对不同的接口而每次都跟着改变,只需要将接口转换的部分通过适配器封装起来就可以了。
Client
:客户端,接口调用方。Target
:目标接口,客户端所期望使用的接口,也是适配器所要适配的接口。Adaptee
:被适配者,系统原有的实现。Adapter
:适配器,适配器需要将被适配者的接口适配成Target
目标接口。类适配器Adapter
是通过继承被适配者Adaptee
来达到适配的目的。
Target
接口:
/**
* 目标接口
*/
public interface Target {
/**
* 适配方法(客户端期望调用的方法)
*/
void request();
}
Adaptee
类:
/**
* 被适配者
*/
public class Adaptee {
/**
* 被适配的方法
*/
public void specificRequest() {
System.out.println("被适配者Adaptee的真实方法调用");
}
}
Adapter
类:
/**
* 适配器
* 通过继承Adaptee并且实现Target接口,达到适配的目的
*/
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
super.specificRequest();
}
}
Client
类:
/**
* 客户端
*/
public class Client {
/**
* 调用target的方法
*/
public void doSomething(Target target) {
target.request();
}
public static void main(String[] args) {
Adapter adapter = new Adapter();
new Client().doSomething(adapter);
}
}
由于Java
是单继承语言,某个类适配器只能服务于一个被适配者,不利于程序的扩展;
并且由于是基于继承的方式,被适配者的所有属性和操作都对适配器暴露,也不利于程序的安全和可控;
所以类适配器的方式其实在实际开发中比较少用。
在对象适配器中,不是通过继承被适配者Adaptee
来适配的,而是通过关联Adaptee
来适配,Adaptee
是Adapter
的成员变量。
目标接口IGameProps
:
/**
* 目标接口:游戏道具
*/
public interface IGameProps {
/**
* 适配方法:计算能够购买的道具数量
*/
void calculate();
}
被适配者Rmb
:
/**
* 被适配者:人民币
*/
public class Rmb {
/**
* 人民币面值
*/
private int count;
public Rmb(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
适配器GameCurrency
:
/**
* 适配器:游戏币
* 通过依赖Rmb并且实现IGameProps接口,达到适配的目的
*/
public class GameCurrency implements IGameProps {
/**
* 人民币对象的引用
*/
private Rmb rmb;
/**
* 游戏币面值
*/
private int count;
public GameCurrency(Rmb rmb) {
this.rmb = rmb;
// 1人民币等于10游戏币
this.count = rmb.getCount() * 10;
}
@Override
public void calculate() {
System.out.println("您拥有游戏币: " + this.getCount() +
", 可以购买玩具(单价2游戏币): " + this.getCount() / 2 + "个");
}
public int getCount() {
return count;
}
}
客户端Client
:
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 充值5人民币
Rmb rmb = new Rmb(5);
// 人民币转游戏币并计算能够购买的道具数量
new GameCurrency(rmb).calculate();
}
}
正如上面的例子描述的那样,游戏道具只能用游戏币购买,不能用人民币直接购买。所以,必须定义一个“游戏币”适配器类,来适配“人民币”。
当我们要用这个适配器再适配其他类时,只要在适配器中增加其他类对象的引用就行,这比继承有更好的扩展性。
对象适配器的优点: