前言
适配器模式与外观模式一样,也属于结构型模式。适配器所谓适配就是定义了一个外界希望的接口,从而使得原来不能工作的那些对象可以一起工作。在软件开发中,如果希望复用一些类,但是需要复用的类与复用环境不符的时候,需要使用适配器模式。更具体的说就是当前系统的行为与数据都正确但是接口不符这样就需要使用适配器模式。从设计角度讲,适配器模式耐无奈之举。这么说也很好理解,因为当需要复用一些类的时候,如果不希望更改外部接口也不希望更改内部系统的行为与数据,那么怎么办呢。前面的设计模式文章中提到开放-封闭原则,要完成功能的扩展必须要么修改原来的代码要么扩展现有的类,而现在这两个条件都不符合,所以只能添加一个额外的接口来适配了,所以可以这么理解,当双方的修改成本都很高的时候就考虑使用设配器接口来完成功能的对接。
在NBA比赛中,如果一个外籍球星加入NBA,而他又不懂英语,而且在短期学会英语也不是一件易事,NBA的其他球员也不懂他的语言,那么在这种情况下,最好的选择当然是找一个翻译比较省事了。而这个翻译
就是这里提到的适配器了。
OK,那么就以NBA外籍球星,比如姚明,加入NBA比赛的场景用代码实现
编码实践
public class AdapterMode{
//抽象球员类
public abstract class Player{
protected String name;
public Player(){}
public Player(String name){this.name = name;}
public abstract void attack();
}
//本土球员
public class NativeNBAPlayer extends Player{
public NativeNBAPlayer(String name){super(name);}
public void attack(){
System.out.println("I am native NBA player, I am attacking!");
}
}
//外籍球员
public class ForeignNBAPlayer extends Player{
public ForeignNBAPlayer(){}
public ForeignNBAPlayer(String name){super(name);}
public void attack(){
System.out.println("我是中国球星,我在攻击!");
}
}
public class Translator{
private String name;
private Player foreignNBAPlayer;
public Translator(String name,Player foreignNBAPlayer){this.name = name;this.foreignNBAPlayer = foreignNBAPlayer;}
public void translatorAttack(){
foreignNBAPlayer.attack();
}
}
//测试代码
public static void main(String[] args){
AdapterMode am = new AdapterMode();
Player nativeNBAPlayer = am.new NativeNBAPlayer("Kobe");
Player foreignNBAPlayer = am.new ForeignNBAPlayer("姚明");
nativeNBAPlayer.attack();
Translator translator = am.new Translator("翻译管官",foreignNBAPlayer);
translator.translatorAttack();
}
}
测试结果:
通过测试代码可以发现Adapter类很好完成了“翻译工作”,当然这只是测试代码,实际开发中可能是两个完全不相关的接口,而为了让这两个接口能够协同工作就可以使用“适配器”来进行接口的适配,这样两个完全不相关的接口就能共同完成一个目标了,这也是适配器存在的意义(在这个例子中,外籍球员与本土球员完成的共同目标是打篮球)。至此,我们就能够对适配器模式做一个简单的总结了:
- 适配器模式通过定义一个外界希望的接口使得原来不相关的类可以协同工作
- 当需要复用的类与复用环境差别较多的时候,可以考虑使用适配器模式
- 当需要协同工作的双方都不愿修改自身的代码或者双方修改的成本较大的时候,可以考虑使用适配器模式
- 适配器模式为客户调用提供了一个统一的接口,使得客户的调用更简单更直接更紧凑