适配器模式(Adapter),将一个类的接口转换成客户希望的另一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
在软件开发中,系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但接口又与复用环境要求不一致的情况。
Target(客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口)。
Adaptee 需要适配的类,想要复用的代码。
Adapter 适配器类,在内部包装一个 Adaptee 对象,把源接口转换成目标接口。
Target 接口
//客户期待的接口
class Target {public void request(){System.out.println("普通请求!");}
}
需要适配的类 Adaptee
class Adaptee {public void specificRequest(){System.out.println("特殊请求!");}
}
适配器类 Adapter,将 Adaptee 转换为 Target 接口
//适配器类
class Adapter extends Target {//建立一个私有的Adaptee对象private Adaptee adaptee = new Adaptee(); //这样就可以把表面上调用request()方法public void request(){//变成实际调用specificRequest() adaptee.specificRequest(); }
}
何时使用适配器模式?
如果想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,应当考虑用适配器模式。两个类所做的事情相同或相似,但是具有不同的接口时要使用它。
外籍球员通过翻译者与本土球员进行交流。
外籍球员类就是要进行适配的类。翻译者就是适配器类。Player 就是目标接口。
球员接口,就是目标接口。
abstract class Player {protected String name;public Player(String name){this.name = name;}public abstract void attack(); //进攻public abstract void defense(); //防守
}
// 前锋
class Forwards extends Player {public Forwards(String name){super(name);}public void attack(){System.out.println("前锋 "+this.name+" 进攻");}public void defense(){System.out.println("前锋 "+this.name+" 防守");}
}
// 中锋
class Center extends Player {public Center(String name){super(name);}public void attack(){System.out.println("中锋 "+this.name+" 进攻");}public void defense(){System.out.println("中锋 "+this.name+" 防守");}
}// 后卫
class Guards extends Player {public Guards(String name){super(name);}public void attack(){System.out.println("后卫 "+this.name+" 进攻");}public void defense(){System.out.println("后卫 "+this.name+" 防守");}
}
外籍中锋(待适配的类)
//外籍中锋
class ForeignCenter {private String name;public String getName(){return this.name;}public void setName(String value){this.name = value;}public void 进攻(){System.out.println("外籍中锋 "+this.name+" 进攻");} public void 防守(){System.out.println("外籍中锋 "+this.name+" 防守");}
}
翻译者类(适配类,将外籍中锋适配到目标接口)
// 实现目标接口所需要的方法
class Translator extends Player {// 包含一个待适配的类private ForeignCenter foreignCenter = new ForeignCenter();public Translator(String name){super(name);foreignCenter.setName(name);}public void attack(){foreignCenter.进攻();}public void defense(){foreignCenter.防守();}
}
适配器模式不能乱用,只有碰到无法改变原有设计和代码的情况时,才考虑适配。
事后控制不如事中控制,事中控制不如事前控制。