20230426 17. 适配器模式 - NBA外籍中锋
介绍
适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式主要解决的问题:简单地说,就是需要的东西就在面前,但却不能使用,而短时间又无法改造它,于是我们就想办法适配它
系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况
在GoF的设计模式中,对适配器模式讲了两种类型,类适配器模式和对象适配器模式,由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而Java、C#、VB.NET等语言都不支持多重继承(C++支持),也就是一个类只有一个父类,所以我们这里主要讲的是对象适配器
- Target(这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口)
- Adaptee(需要适配的类)
- Adapter(通过在内部包装一个Adaptee对象,把源接口转换成目标接口)
使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式
两个类所做的事情相同或相似,但是具有不同的接口时要使用它
在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同时就使用它。那有没有设计之初就需要考虑用适配器模式的时候?当然有,比如公司设计一系统时考虑使用第三方开发组件,而这个组件的接口与我们自己的系统接口是不相同的,而我们也完全没有必要为了迎合它而改动自己的接口,此时尽管是在开发的设计阶段,也是可以考虑用适配器模式来解决接口不同的问题。
如果能事先预防接口不同的问题,不匹配问题就不会发生;在有小的接口不统一问题发生时,及时重构,问题不至于扩大;只有碰到无法改变原有设计和代码的情况时,才考虑适配。事后控制不如事中控制,事中控制不如事前控制。
代码示例
Target类
@Data
public abstract class Player {
protected String name;
public Player(String name) {
this.name = name;
}
public abstract void attack();
public abstract void defense();
}
Target实现类
public 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 + " 防守");
}
}
Target适配类
/**
* 翻译者类
*
*/
public 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.防守();
}
}
需要适配的类
/**
* 外籍中锋
*
*/
@Data
public class ForeignCenter {
private String name;
public void 进攻() {
System.out.println("外籍中锋 " + this.name + " 进攻");
}
public void 防守() {
System.out.println("外籍中锋 " + this.name + " 防守");
}
}
客户端
public class Test {
public static void main(String[] args) {
Player forwards = new Forwards("巴蒂尔");
forwards.attack();
Player center = new Translator("姚明");
center.attack();
center.defense();
}
}