「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
1.什么是适配器模式
适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。这种类型的设计模式属于结构型模式。
举个例子:在生活中我们的家用电压一般是220V,我们手机的充电电压通常是5v,如果直接把家用电压接到电池接到电池两极直接充电的话,电池会烧掉。这个时候我们的充电就扮演一个适配器的角色,使得家用电源能够安全的给手机电池充电
2.适配器模式原理
2.1组成
适配器模式(Adapter Pattern)包含以下主要角色:
- 目标(Target)接口:当前系统业务所期望的接口,它可以是具体的类、抽象类或接口。
- 适配者(Adaptee)类:它是被适配的对象,已有接口,但和目标接口不兼容。
- 适配器(Adapter)类:它是一个转换器,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
2.2 分类
适配器模式(Adapter Pattern)主要分为三类
- 类适配器模式
- 对象适配器模式
- 接口适配器模式
3 类适配器模式
3.1 原理
适配器(Adapter)类通过继承适配者(Adaptee)类,并实现目标(Target)接口,完成适配者类到目标接口的转换。下面代码以给手机充电为例
3.2 类图
3.3 核心代码
目标接口:
//目标接口
public interface IVoltage5V {
public int output5V();
}
适配者:
//被适配的类
public class Voltage220V {
//家庭电源 输出220V的电压
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
适配器:
//适配器类
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
//获取到220V电压
int srcV = output220V();
int dstV = srcV / 44 ; //转成 5v
return dstV;
}
}
客户端:
public class Phone {
//充电 调用目标接口即可
public void charging(IVoltage5V iVoltage5V) {
if(iVoltage5V.output5V() == 5) {
System.out.println("电压为5V, 可以充电~~");
} else if (iVoltage5V.output5V() > 5) {
System.out.println("电压大于5V, 不能充电~~");
}
}
}
3.4 总结
- Java是单继承的,他要继承适配者类,所以目标接口必须要是接口类,有一定局限性。
- 因为适配器继承了适配者类,所以会导致适配器中可以直接访问适配者类的一些其他方法或变量,增加使用成本,但同样地它也可以重写这些方法。
4.对象适配器模式
4.1 原理
与上面类适配器模式差不多,不同的是,适配器是通过持有被适配类(适配者)的实例,如以成员变量的方式持有,然后实现目标接口,从而完成适配者 ---》 目标接口的兼容。
4.2 类图
4.3 核心代码
这里只有适配者和适配器的引用关系发生变化,所以我只贴出这部分代码 适配者(也无需改变)
//被适配的类
public class Voltage220V {
//输出220V的电压,不变
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
适配器
//适配器类
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V; // 关联关系-聚合
//通过构造器,传入一个 Voltage220V 实例
public VoltageAdapter(Voltage220V voltage220v) {
this.voltage220V = voltage220v;
}
@Override
public int output5V() {
int dst = 0;
if(null != voltage220V) {
int src = voltage220V.output220V();//获取220V 电压
System.out.println("使用对象适配器,进行适配~~");
dst = src / 44;
System.out.println("适配完成,输出的电压为=" + dst);
}
return dst;
}
}
4.4 总结
- 对象适配器和类适配器本质上思想差不多,只不过实现方式不同。根据合成复用原则,使用组合替代继承, 所以它解决了类适配器必须继承适配者类的局限性问题,同时也不在要求目标接口类必须是接口。
- 是相对于类适配器一种更灵活的实现方式。
5.缺省适配器模式
5.1 原理
缺省适配器模式(接口适配器模式):缺省适配模式为一个接口提供缺省实现,通常是一个抽象类作为中间层实现接口所有的方法,默认为空实现,(在jdk1.8之后,接口也可以实现接口,给一个默认方法),这样我们就可以从这个缺省实现进行扩展,而不必从原有接口进行扩展。当原接口中定义的方法太多,而其中大部分又不被需要时,这种模式非常实用。
5.2 类图
5.3 核心代码
接口
public interface Interface4 {
public void m1();
public void m2();
public void m3();
public void m4();
}
抽象类
//在AbsAdapter 我们将 Interface4 的方法进行默认实现
public abstract class AbsAdapter implements Interface4 {
//默认实现
public void m1() {
}
public void m2() {
}
public void m3() {
}
public void m4() {
}
}
//继承类
public class AbsAdapterImpl extends AbsAdapter{
@Override
public void m1() {
System.out.println("我选择性实现了 m1()方法");
}
}
5.4 总结
适用于当原接口中定义的方法太多,而其中大部分又不被需要时,使用这种模式选择性的实现一些方法。
6 应用案例
SpringMvc中的HandlerAdapter。
public class DispatcherServlet extends FrameworkServlet {
@Nullable
private List<HandlerAdapter> handlerAdapters;
//把所有的HandlerAdapter放到List<HandlerAdapter>中去
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
} else {
try {
HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
} catch (NoSuchBeanDefinitionException var3) {
}
}
if (this.handlerAdapters == null) {
this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
if (this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerAdapters declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
}
}
}
//通过handlerMappings 给每个controller 分配对应的 handle
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
//遍历 找到符合条件的适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
// 通过HandlerAdapter处理 返回对应的 ModelAndView 对象 通过HandlerAdapter把handles
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
HandlerAdapter 的实现子类使得每一种Controller有一种对应的适配器实现,每种Controller 有不同的实现方式,扩展controller时,只需要增加HandlerAdapter的实现类即可。