适配器模式:将一个类的接口转化为客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
举个栗子:姚明最初在NBA听不懂英文,这时就需要一个翻译,这个翻译就是姚明的适配器。
在软件开发中,系统的数据和行为都正确,但接口不符时,我们应该考虑使用适配器,目的是使控制范围外的一个原有对象与某个接口匹配。适配器模式主要用于一些现存的类,但是接口又与复用环境要求不一致的情况。
适配器模式分为两种,类适配器和对象适配器,由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而Java不支持多继承,所以要用对象适配器。
例子:
球员类,有进攻,防守方法。
public abstract class Player {
public String name;
public Player(String name) {
this.name = name;
}
public abstract void attack();
public abstract void defense();
}
前锋类:
public class Forward extends Player {
public Forward(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("前锋" + name + "进攻");
}
@Override
public void defense() {
System.out.println("前锋" + name + "防守");
}
}
后卫类Guards和前锋类类似......
外籍中锋类,姚明为外籍队员,使用中文。
public class ForeignCenter {
public String name;
public void 进攻() {
System.out.println("外籍中锋" + name + "进攻");
}
public void 防守() {
System.out.println("外籍中锋" + name + "防守");
}
}
姚明听不懂英文,所以需要一个翻译(适配器),翻译者将attack翻译为进攻,告诉外籍中锋:
public class Translator extends Player {
private ForeignCenter foreignCenter = new ForeignCenter();
public Translator(String name) {
super(name);
foreignCenter.name = name;
}
@Override
public void attack() {
foreignCenter.进攻();
}
@Override
public void defense() {
foreignCenter.防守();
}
}
客户端代码:
public class AdapterTest {
public static void main(String[] args) {
Player p1 = new Forward("巴蒂尔");
p1.attack();
Player p2 = new Guards("麦克格雷迪");
p2.attack();
Player p3 = new Translator("姚明");
p3.attack();
p3.defense();
}
}
输出:
前锋巴蒂尔进攻
后卫麦克格雷迪进攻
外籍中锋姚明进攻
外籍中锋姚明防守
使用翻译类进行翻译,这样姚明就能听得懂了。
何时使用适配器模式?
在想使用一个已经存在的类,但如果它的接口,也就是它的方法和你要求的不相同时,就应该考虑使用适配器模式。
两个类所做的事情相同或类似,但是具有不同的接口时需要使用它。而且由于类都共享同一个接口,客户端代码统一调用同一个接口就可以了,这样应该可以更简单,更直接,更紧凑。
我们通常是在软件开发后期或维护期再来考虑使用它。接口不相同时,首先不应该考虑使用适配器,而是应该考虑通过重构统一接口。在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同时就使用它。
在设计之初,如果考虑使用第三方开发组件,而这个组件的接口与我们自己的系统接口是不相同的,而我们也完全没有必要为了迎合它而改动自己的接口,此时尽管是在开发的设计阶段,也可以考虑使用适配器模式来解决接口不匹配的问题。