适配器模式
适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
这里我们学习的是对象适配器。
Target类
这是客户所期待的接口.目标可以是具体的或抽象的类,也可以是接口。
public abstract class Target {
public void request() {
System.out.println("普通请求");
}
}
Adaptee(需要适配的类)
public class Adaptee {
public void specificRequest() {
System.out.println("特殊请求");
}
}
Adapter
通过在内部包装一个Adaptee对象,把源接口转换成目标接口。
适配器实现目标接口,组装待适配对象。
public class Adapter extends Target {
/**
* 建立一个私有的Adaptee对象
*/
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
// 这样就可以把表面上调用request方法变成实际上调用specificRequest方法
adaptee.specificRequest();
}
}
客户端
public class Client {
public static void main(String[] args) {
// 对客户端来说,调用的就是Target的request
Target target = new Adapter();
target.request();
}
}
什么时候该使用适配器模式?
在想使用一个已经存在的类,如果它的接口要求的不相同时,就应该考虑使用适配器模式。两个类所做的事情相同或相似,但是具有不同的接口要使用它。
客户代码可以统一调用同一接口,这样更简单、更直接、更紧凑。
适配器模式有种“亡羊补牢”的感觉。
接口不相同时,首先不应该考虑用适配器,而是应该考虑通过重构统一接口。在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同时就使用它。
篮球翻译适配器案例
球员
//球员
public abstract class Player {
protected String name;
public Player(String name) {
this.name = name;
}
//进攻
public abstract void attack();
// 防守
public abstract void defense();
}
前锋、中锋、后卫
/**
* 前锋
*/
public class Forwards extends Player{
public Forwards(String name) {
super(name);
}
@Override
public void attack() {
System.out.println(String.format("前锋 %s进攻", name));
}
@Override
public void defense() {
System.out.println(String.format("前锋 %s防守", name));
}
}
/**
* 中锋
*/
public class Center extends Player{
public Center(String name) {
super(name);
}
@Override
public void attack() {
System.out.println(String.format("中锋 %s进攻", name));
}
@Override
public void defense() {
System.out.println(String.format("中锋 %s防守", name));
}
}
/**
* 后卫
*/
public class Guards extends Player{
public Guards(String name) {
super(name);
}
@Override
public void attack() {
System.out.println(String.format("后卫 %s进攻", name));
}
@Override
public void defense() {
System.out.println(String.format("后卫 %s防守", name));
}
}
客户端
public class Client {
public static void main(String[] args) {
Player forwards = new Forwards("巴蒂尔");
forwards.attack();
Player guards = new Guards("麦克格雷迪");
guards.attack();
Player center = new Center("姚明");
center.attack();
center.defense();
}
}
外籍中锋
// 外籍中锋
public class ForeignCenter {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 外籍中锋的方法与中锋的方法不同
public void myAttack() {
System.out.println(String.format("外籍中锋 %s进攻", name));
}
// 外籍中锋的方法与中锋的方法不同
public void myDefense() {
System.out.println(String.format("外籍中锋 %s防守", name));
}
}
翻译者
// 翻译者
public class Translator extends Player{
/**
* 声明并实例化一个内部“外籍中锋”对象,表名翻译者和外籍球员有关联
*/
private ForeignCenter foreignCenter = new ForeignCenter();
public Translator(String name) {
super(name);
foreignCenter.setName(name);
}
@Override
public void attack() {
// 翻译者将attach()->myAttack()
foreignCenter.myAttack();
}
@Override
public void defense() {
// 翻译者将defense()->myDefense()
foreignCenter.myDefense();
}
}
客户端改写
public class Client {
public static void main(String[] args) {
Player forwards = new Forwards("巴蒂尔");
forwards.attack();
Player guards = new Guards("麦克格雷迪");
guards.attack();
// Player center = new Center("姚明");
// center.attack();
// center.defense();
Player translator = new Translator("姚明");
translator.attack();
translator.defense();
}
}
注:本文内容源自程杰的《大话设计模式》