在学习SpringMVC时,发现了HandlerAdapter这个类采用了之前听说过的适配器模式, 因此专门来学习一下适配器模式
参考博客:
一.适配器模式概念
适配器模式是将某个类的接口转换成客户希望的另一种接口. 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁, 它结合了两个接口的功能.
用编程概念解释就是, 你有一个接口,和其实现类, 但是这个接口实现的功能并不能完全满足你的需要, 于是你实现了另一个接口, 这个接口只需要在前一个接口实现的功能上加以修改就能满足你的需要, 但是两个接口的功能是不能兼容的. 于是就有了适配器模式, 来让两个接口兼容.
用一般解释适配器的例子, 通俗讲就是 你有一个220V的电压电源, 但是你的手机只能支持5V电压充电, 于是你需要有一个能将220V电压转换成5V电压的适配器, 来让你手机充电.
二.适配器模式定义
适配器模式是结构型模式
三类适配器模式: 类适配器模式 , 对象适配器模式 , 接口适配器模式
适配器模式的术语: 1.目标(Target)接口: 当前系统业务所期待的接口,它可以是抽象类或接口
2.适配者(Adaptee)类: 它是被访问和适配的现有组件库中的组件接口
3.适配器(Adapter)类: 它是一个转换器,通过继承或引用Adaptee的对象, 把Adaptee接口转换成目标接口.
使用场景:
1.系统需要使用现有的类, 而这些类的接口不符合系统的需要
2.想要建立一个可以重复使用的类, 用于一些彼此之间没有太大关联的类, 包括一些可能在将来引进的类一起工作.
3.需要一个统一的输出接口,而输入端的类型不可预知.
三.适配器模式的实现
1.类适配器模式:
Adapter类, 通过继承Adaptee类, 并实现Taget接口 , 完成Adaptee >>> Target的适配
(1)首先实现Adaptee类
这是一个输出220V电压的电源
public class Voltage220 { public int output220V(){ int src = 220; System.out.println("输出电压:"+src+"V"); return src; }}
(2)再实现Target接口
这个接口要实现一个输出5V的电源
public interface Voltage5 { int output5V();}
(3)然后实现类适配器, 让两者兼容
适配器通过继承Adaptee类, 实现Target接口,来将两者结合
//适配器的第一种方式: 类适配器模式public class VoltageAdapter extends Voltage220 implements Voltage5 { @Override public int output5V() { int src = output220V(); System.out.println("适配器转换电压"); int dst = src/44; System.out.println("适配器输出电压:"+dst+"V"); return dst; }}
问题: 1.为啥要先继承Voltage220,而不是直接实现Voltage5接口,然后在类里调用Voltage220呢?
答:这是适配器的第二种实现方式, 对象的适配器模式, 也是适配器模式的一种
2.为啥不能让Voltage220直接实现Voltage5的接口呢?
答:因为在使用Voltage220的时候,有可能Voltage5接口是不需要的累赘,或者你还要实现其他接口.另外,这样会增加耦合性, 使Voltage220难以扩展其它多的功能. 比如下次如果你还要实现一个Voltage10的接口,Voltage20的接口,不可能一直往上面实现.
2.对象适配器模式
Adapter类持有Adaptee类, 实现Target接口, 完成Adaptee >>> Target的适配
(1)实现Adaptee类: 与上面代码一样
public class Voltage220 { public int output220V(){ int src = 220; System.out.println("输出电压:"+src+"V"); return src; }}
(2)Target接口:
public interface Voltage5 { int output5V();}
(3)Adapter实现:
//适配器的第二种方式: 对象适配器模式public class VoltageAdapter2 implements Voltage5 { private Voltage220 voltage220; public VoltageAdapter2(Voltage220 voltage220){ this.voltage220 = voltage220; } @Override public int output5V() { int dst = 0; if(null != voltage220){ int src = voltage220.output220V(); System.out.println("适配器转换电压"); dst = src/44; System.out.println("适配器输出电压"+dst+"V"); } return dst; }}
注意:与装饰器模式的区别, 装饰器持有的对象和装饰器实现的是同一接口, 且装饰器模式的目的是增强功能
3.接口的适配器模式:
也叫认识适配器模式或缺省适配器模式
当你要使用一个接口的提供的某一个方法, 而不需要全部实现接口提供的方法时, 可以先设计一个抽象类实现接口, 并为接口中的每个方法默认实现(空实现), 那么该抽象类的子类可以有选择地覆盖父类的某些方法来实现其想要的方法, 而不是实现全部方法.
(1)实现Adaptee类:
public class Voltage220 { public int output220V(){ int src = 220; System.out.println("输出电压:"+src+"V"); return src; }}
(2)设计Target接口, 设计一个抽象类来空实现Target接口的方法:
public interface SuperVoltage { int output5V(); int output10V(); int output20V(); int output40V(); int output220V();}
//适配器模式的第三种: 接口适配器模式, 或者叫认识适配器模式, 缺省适配器模式public abstract class SuperVoltageAdapter implements SuperVoltage{ @Override public int output5V() { return 0; } @Override public int output10V() { return 0; } @Override public int output20V() { return 0; } @Override public int output40V() { return 0; } @Override public int output220V() { return 0; }}
(3)抽象类的子类就可以有选择地实现其需要的方法:
①5V输出:
public class VoltageAdapter3 extends SuperVoltageAdapter { private Voltage220 voltage220; public VoltageAdapter3(Voltage220 voltage220){ this.voltage220 = voltage220; } @Override public int output5V(){ int dst = 0; if(voltage220 != null){ int src = voltage220.output220V(); dst = src/44; System.out.println("适配器转换电压"); } return dst; }}
②10V输出:
public class VoltageAdapter3 extends SuperVoltageAdapter { private Voltage220 voltage220; public VoltageAdapter3(Voltage220 voltage220){ this.voltage220 = voltage220; } @Override public int output10V(){ int dst = 0; if(voltage220 != null){ int src = voltage220.output220V(); dst = src/22; System.out.println("适配器转换电压"); } return dst; }}
四.适配器模式的应用
该段取自博客:
SpringMVC中的适配器模式:
在SpringMVC中 , DispatcherServlet是用户, HandlerAdapter是Target接口, Controller是Adaptee
所以SpringMVC实现了多个适配器,来将Controller转换适应HandlerAdapter接口
(1)Target: HandlerAdapter接口的方法
public interface HandlerAdapter { boolean supports(Object var1); ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; long getLastModified(HttpServletRequest var1, Object var2);}
supports方法是判断Controller是否是该适配器符合的Controller类型
handle方法 来执行Controller中的请求处理
(2)Adaptee: SpringMVC中的Controller实现类
这里不提供具体代码, 只提供有哪些类型
- AbstractController
- AbstractUrlViewController
- MultiActionController
- ParameterizableViewController
- ServletForwardingController
- ServletWrappingController
- UrlFilenameViewController
(3)Adapter: SpringMVC中的适配器实现
- AbstractHandlerMethodAdapter
- HttpRequestHandlerAdapter
- RequestMappingHandlerAdapter
- SimpleControllerHandlerAdapter
- SimpleServletHandlerAdapter
SpringMVC中如何实现适配的:
当Spring容器启动后,会将所有定义好的适配器对象存放在一个List集合中,当一个请求来临时,DispatcherServlet 会通过 handler 的类型找到对应适配器,并将该适配器对象返回给用户,然后就可以统一通过适配器的 hanle() 方法来调用 Controller 中的用于处理请求的方法。
通过适配器模式我们将所有的controller
统一交给 HandlerAdapter
处理,免去了写大量的 if-else
语句对 Controller
进行判断,也更利于扩展新的 Controller
类型。