23种设计原则之-----适配器模式


适配器模式 ( Adapter Pattern )又叫做变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作,属于结构型设计模式。

原文: Convert the interface of a class into another interface clients expect. Adapter lets classes work
解释:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

也就是说,当前系统存在两种接口A和B ,客户只支持访问A接口,但是当前系统没有A接口对象,但是有B接口对象,但客户无法识别B接口,因此需要通过一个适配器C,将B接口内容转换成A接口,从而使得客户能够从A接口获取得到B接口内容。
在软件开发中,基本上任何问题都可以通过增加一个中间层进行解决。适配器模式其实就是一一个中间层。综上,适配器模式其实起着转化/委托的作用,将一种接口转化为另一种符合需求的接口。

适配器模式的应用场景

提供一个转换器(适配器) , 将当前系统存在的一个对象转化为客户端能够访问的接口对象。适配器适用于以下几种业务场景:
1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成
功能类似而接口不相同情况下的解决方案。有点亡羊补牢的感觉。
生活中也非常的应用场景,例如电源插转换头、手机充电转换头、显示器转接头。
在这里插入图片描述
适配器模式一般包含三种角色:
目标角色( Target) : 也就是我们期望的接口;
源角色( Adaptee) : 存在于系统中,内容满足客户需求(需转换),但接口不匹配的接口实例;
适配器( Adapter ):将源角色( Adaptee )转化为目标角色( Target )的类实例;
适配器模式各角色之间的关系如下:
假设当前系统中,客户端需要访问的是Target接口,但Target接口没有一个实例符合需求 ,而Adaptee实例符合需求;但是客户端无法直接使用Adaptee (接口不兼容) ; 因此,我们需要一个适配器( Adapter )来进行中转,让Adaptee能转化为Target接口形式;
适配器模式有3种形式:类适配器、对象适配器、接口适配器。

类适配器

类适配器的原理就是通过继承来实现适配器功能。具体做法:让Adapter实现Target接口,并且继承Adaptee ,这样Adapter就具备Target和Adaptee 的特性,就可以将两者进行转化。下面来看UML类图:
在这里插入图片描述
下面我们以一个示例进行讲解 ,来看下该示例分别用类适配器,对象适配器和接口适配器是怎样进行代码实现。在中国民用电都是220V交流电,但我们手机使用的锂电池使用的5V直流电。因此,我们给手机充电时就需要使用电源适配器来进行转换。下面我们有代码来还原这个生活场景,创建Adaptee角色,需要被转换的对象AC220类,表示220V交流电:

public class AC220 {
	public int outputAC220V0{
		int output = 220;
		System.outprintIn("输出电压" + output + "V"); 
		}
	return output;
}

创建Target角色DC5接口,表示5V直流电的标准:

public interface DC5 {
	int outoupDC5V0;
}

创建Adapter角色电源适配器PowerAdapter类:

public class PowerAdapter extends AC220 implements DC5 {
	public int output5V0 {
		int adapterInput = super.outputAC220V0;
		int adapterOutput = adapterinput / 44;
		System.out.println("使用Adapter输入AC" + adapterInput + "V输出DC" + adapterOutput + "V");
	return adapterOutput;
	}
}

客户端测试代码:

public static void main(StringD args) {
	DC5 adapter = new PowerAdapter0;
	adapter.output5V0;
}

上面的案例中,通过增加PowerAdapter电源适配器,实现了二者的兼容。

对象适配器

对象适配器的原理就是通过组合来实现适配器功能。具体做法:让Adapter实现Target接口,然后内部持有Adaptee实例,然后再Target接口规定的方法内转换Adaptee。
在这里插入图片描述
代码只需更改适配器( Adapter )实现,其他与类适配器致:

public class PowerAdapter implements DC5 {
	private AC220 ac220;
	public PowerAdapter(AC220 ac220) {
	this.ac220 = ac220;
	}
	public int output5V0 {
		int adapterlnput = ac220.outputAC220V0;
		int adapterOutput = adapterinput / 44;
		System. out printIn("使用Adapter输入AC" + adapterlnput + "V输出DC" + adapterOutput + "V");
	return adapterOutput;
	}
}

接口适配器

接口适配器的关注点与类适配器和对象适配器的关注点不太一样,类适配器和对象适配器着重于将系统存在的一个角色( Adaptee )转化成目标接口( Target )所需内容,而接口适配器的使用场景是解决接口方法过多,如果直接实现接口,那么类会多出许多空实现的方法,类显得很臃肿。此时,使用接口适配器就能让我们只实现我们需要的接口方法,目标更清晰。
在这里插入图片描述
接口适配器的主要原理就是原理利用抽象类实现接口,并且空实现接口众多方法。下面我们来接口适配器的源码实现,首先创建Target角色DC类:

public interface DC {
	int output5V();
	int output12V();
	int output24V();
	int output36V();
}

创建Adaptee角色AC220类:

public class AC220 {
	public int outputAC220V( ){
	int output = 220;
	system.out.printin("输出电压”+ 220 + "V");
	return output;
	}
}

创建Adapter角色PowerAdapter类:

public class PowerAdapter implements DC {
	private AC220 ac220;
	public Power Adapter(AC220 ac220) {
	this.ac220 = ac220;
	}
	public int output5V() {
	int adapterInput = ac220.outputAC220V();
	int adapteroutput = adapterInput / 44;
	System.out.println("使用Adapter输入AC" + adapterInput + "V,输出DC" + adapteroutput + "V");
	return adapteroutput;
	}
	public int output12V() {
		return 0;
	}
	public int output24V() {
		return 0;
	}
	public int output36V() {
		return 0;
	}
}

客户端代码:

public class Test{
	public static void main(string[] args) {
	DC adapter = new Power Adapter( new 		AC220();
	adapter .output5V();
	}
}

适配器模式在源码中的体现

Spring中适配器模式也应用得非常泛,例如: SpringAOP中的AdvisorAdapter类,它有三个实现类MethodBeforeAdviceAdapter. AfterReturningAdviceAdapter 和ThrowsAdviceAdapter ,先来看顶层接口AdvisorAdapter的源代码:

package org.springframework.aop.framework .adapter;
import org.aopalliance.aop.Advice;
import	org.aopaliance.intercept.MethodInterceptor;
import org.springframework. aop.Advisor;
public interface Advisoradapter {
	boolean supportsAdvice(Advice var1) ;
	MethodInterceptor getInterceptor(Advisor var1) ;
}

再看MethodBeforeAdviceAdapter类:

Class MethodBeforeadviceAdapter implements Advisoradapter, Serializable {
	MethodBeforeadviceadapter() {}
	public boolean supportsadvice(Advice advice) {
	return advice instanceof MethodBeforeadvice;
	}
	public MethodInterceptor getInterceptor(Advisor advisor) {
	MethodBeforeadvice advice = (MethodBeforeAdvice) advi sor. getAdvice();
	return new MethodBefor eAdviceInterceptor(advice);
	}
}

其它两个类我这里就不把代码贴出来了。Spring会根据不同的AOP配置来确定使用对应的Advice,跟策略模式不同的一一个方法可以同时拥有多个Advice.

适配器模式和装饰器模式对比

装饰器和适配器模式都是包装模式( Wrapper Pattern ) , 装饰器也是一种特殊的代理模式。

装饰器模式适配器模式
形式是一种非常特别的适配器模式没有层级关系,装饰器模式有层级关系
定义装饰器和被装饰器都实现同一个接口,主要目的是为了扩展之后依旧保留OOP关系适配器和被适配者没有必然的联系,通常是采用继承或代理的形式进行包装
关系满足is-a的关系满足has-a的关系.
功能注重覆盖、扩展注重兼容、转换
设计前置考虑.后置考虑.

适配器模式的优缺点

优点:
1、能提高类的透明性和复用;现有的类复用但不需要改变。
2、目标类和适配器类解耦,提高程序的扩展性。
3、在很多业务场景中符合开闭原则。
缺点:
1、适配器编写过程需要全面考虑,可能会增加系统的复杂性。
2、增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值