适配器模式
概述
- 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以共同工作。
- 适配器模式主要分为两种:类适配器和对象适配器
适配器模式的基本构成
- 01)目标角色( Target): 定义Client 使用的接口,可以是具体或抽 象的类、或是接口。
- 02)被适配角色( Adaptee): 这个角色有一个已存在并使用了的接口,而这个接口是需要适配的
- 03)适配器角色( Adapter) :这个适配器模式的核心。它将被适配角色已有的接口转换为目标 角色希望的接口。
适配器模式特性
- 实现对象外部接口的转换
- 复用现有的某些类
- 软件设计阶段应优先考虑接口统一,避免适配器模式的滥用.
适配器的利:
- 能提高类的透明性和复用,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,现有的类复用但不需要改变,而且提高了适配者的复用性,同一适配者类可以在多个不 同的系统中复用。
- 目标类和适配器类解耦,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构,提高程序扩展性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改原有代码的基础上,增加新的适配器,符合开闭原则。
适配器的弊:
- 增加系统代码可读的难度。
- 只能一对一,不能一对多(一次最多只能适配一个适配者类,不能同时适配多个适配者。)
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性。
类适配器原理:
- 创建一个目标(Target)接口或者目标(Target)抽象类,也可以是一个具体类
- 创建一个适配器类(Adapter),同时继承被适配类(Adaptee)并实现目标接口
- 在适配器类中重写目标接口或者目标抽象类的方法
- 在重写后的方法中通过调用被适配类访问所需要的方法
相关代码:
/**
* 目标接口
* @author Savior.D
*/
interface Target {
public abstract void request();
}
/**
* 需要被适配的类
*/
class Adaptee {
public void adpateeRequest() {
System.out.println("我是被适配者的请求方法");
}
}
/**
* 适配器
*/
class Adapter extends Adaptee implements Target {
//重写目标接口中的方法
@Override
public void request() {
//通过适配器类调用访问所需要被适配类中的方法
super.adpateeRequest();
}
}
对象适配器原理:
- 创建一个目标(Target)接口
- 创建一个适配器类(Adapter)实现目标接口
- 在适配器类中重写目标接口中的方法
- 在类中创建私有的被适配类的对象
- 在重写后的方法中通过调用被适配类的对象访问所需要的方法
相关代码:
/**
* 目标接口
*
* @author Savior.D
*/
interface Target {
public abstract void request();
}
/**
* 需要被适配的类
*/
class Adaptee {
public void adpateeRequest() {
System.out.println("我是被适配者的请求方法");
}
}
/**
* 适配器
*/
class Adapter implements Target {
//创建私有的被适配类的对象
private static Adaptee adaptee;
@Override
public void request() {
//通过被适配器类的对象调用其中所需要的方法
adaptee.adpateeRequest();
}
接下来让我们看一个具体的场景设计样例子:
利用适配器模式实现外籍球员通过翻译者(相当于实现语言转换的适配器) ,在接受不同训练指令(即接口调用)时,与其他球员以一致的训练指令进行训练的过程。在.上述设计的场景中将球员分为三类,即前锋、中锋、后卫,同时每类球员的训练指令简化为:进攻和防守两种。此外,设定有一位外籍中锋球员,该球员通过翻译接受命令进行训练。
具体类图:
球员类的代码:
**
*球员类,所有非外籍球员的父类
*/
class BasketballPlayer{
private String name;
public BasketballPlayer(String name) {
super();
this.setName(name);
}
public BasketballPlayer() {
super();
}
public void attack() {
System.out.println("进攻");
}
public void defense() {
System.out.println("防守");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 非外籍前锋类
*/
class Forward extends BasketballPlayer{
public Forward() {
super();
}
public Forward(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("前锋"+super.getName()+"进攻");
}
@Override
public void defense() {
System.out.println("前锋"+super.getName()+"防守");
}
}
/**
*非外籍控球后卫
*/
class PointGuard extends BasketballPlayer{
public PointGuard() {
super();
}
public PointGuard(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("控球后卫"+super.getName()+"进攻");
}
@Override
public void defense() {
System.out.println("控球后卫"+super.getName()+"防守");
}
}
/**
* 非外籍中锋
*/
class CentreForward extends BasketballPlayer{
public CentreForward() {
super();
}
public CentreForward(String name) {
super(name);
}
@Override
public void attack() {
System.out.println("中锋"+super.getName()+"进攻");
}
@Override
public void defense() {
System.out.println("中锋"+super.getName()+"防守");
}
}
运用适配器模式的翻译者代码:
/**
* 此处运用类适配器的设计模式
* 这里的翻译者就相当于一个适配器
* 通过他 转换外籍球员将可以正常的进攻和防守
*/
class Translator extends BasketballPlayer{
//创建外籍球员的实例
private ForeignCentreForward fcf=new ForeignCentreForward();
public Translator() {
super();
}
public Translator(String name) {
fcf.setName(name);
}
/* 重写球员类的进攻方法
* 在里面通过外籍球员实例的调用实现外籍球员的进攻
* @see com.duanping.demos.BasketballPlayer#attack()
*/
@Override
public void attack() {
fcf.gongji();
}
/* 重写球员类的防守方法
* 在里面通过外籍球员实例的调用实现外籍球员的防守
* @see com.duanping.demos.BasketballPlayer#defense()
*/
@Override
public void defense() {
fcf.fanshou();
}
}
等待被匹配的外籍球员的相关代码:
/**
* 外籍中锋,有自己的进攻方式和防守方式,但是因为是外籍球员,
* 沟通不便,进攻防守方面会受到影响
*/
class ForeignCentreForward{
private String name;
public ForeignCentreForward() {
super();
}
public ForeignCentreForward(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//外籍球员的进攻,等待被匹配
public void gongji() {
System.out.println("外籍中锋"+name+"进攻");
}
//外籍球员的防守,等待被匹配
public void fanshou() {
System.out.println("外籍中锋"+name+"防守");
}
}
如果觉得本篇文章对你有所帮助,可以点个赞~,谢谢支持