1、适配器模式的理解
适配器模式可以理解为有两个现成的类Adaptee和Target,它们两个是不能动的,要求必须使用B这个类来实现一个功能,但是A的内容是能复用的,这个时候我们需要编写一个转换器
适配器模式
- Adaptee:被适配者,现有的接口或者类;
- Adapter:适配器类,适配器模式的核心,转换作用
- Target:目标接口或者类
适配器模式的实现步骤
- 定义目标接口,即客户端所期望的接口。
- 定义适配器类,继承目标接口并包含一个适配者对象。
- 在适配器类中实现目标接口的方法,调用适配者对象的相关方法进行适配。
- 在客户端中使用适配器类进行操作。
适用场景
- 继承:需要用到别人的类,但是不能修改
- 多适配者:多个不同的对象,需要让他们具有相同的方法
- 缺省形式
适配器模式有类适配器和对象适配器两种方式,一般采用前者
2、继承场景
来公司第二天,写一个简单的业务,看到同事写的接口中5个方法有3个正好可以用的,但是还需要另外新增一个,于是我便开始了改造(新增一个方法);提交后同事大发雷霆,谁让你新增的,新增了这个方法,这个接口就失去了本来的意思。。。。。。
我去***,那算了,我还是自己写一个吧,想想怎么能在不懂他的接口前提下,复用一下他的代码,那边使用适配器模式
//同事的接口为被适配者
public interface Adaptee{
void method1();
void method2();
void method3();
void method4();
void method5();
}
public class AdapteeImpl implements Adaptee {
@Override
public void method1() {
System.out.println("method1 execute......");
}
@Override
public void method2() {
System.out.println("method2 execute......");
}
@Override
public void method3() {
System.out.println("method3 execute......");
}
@Override
public void method4() {
System.out.println("method4 execute......");
}
@Override
public void method5() {
System.out.println("method5 execute......");
}
}
//我需要使用的接口为目标接口
public interface Target{
void method1();
void method2();
void method3();
void method6();
}
//构建适配器类Adapter
//方式一:类适配器方式
public class Adapter1 extends AdapteeImpl implements Target {
@Override
public void method6() {
System.out.println("method6 execute......");
}
}
public class Client {
public static void main(String[] args) {
Target target = new Adapter1();
target.method1();
target.method2();
target.method3();
target.method6();
}
}
//方式二:对象适配器方式
public class Adapter2 implements Target {
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void method1() {
adaptee.method1();
}
@Override
public void method2() {
adaptee.method2();
}
@Override
public void method3() {
adaptee.method3();
}
@Override
public void method6() {
System.out.println("method6 execute......");
}
}
public class Client {
public static void main(String[] args) {
Target target = new Adapter2(new AdapteeImpl());
target.method1();
target.method2();
target.method3();
target.method6();
}
}
3、多适配者
多个适配者,适配同一个目标接口,为每一个适配者创建一个适配器
这种是最常用的方式,在springMVC和AOP中都有用到,后面会进行解析
例:新能源汽车的发动机有电能发动机(Electric Motor)和光能发动机(Optical Motor)等,各种发动机的驱动方法不同,例如,电能发动机的驱动方法 electricDrive() 是用电能驱动,而光能发动机的驱动方法 opticalDrive() 是用光能驱动,它们是适配器模式中被访问的适配者。
客户端希望用统一的发动机驱动方法 drive() 访问这两种发动机,所以必须定义一个统一的目标接口 Motor,然后再定义电能适配器(Electric Adapter)和光能适配器(Optical Adapter)去适配这两种发动机。
package adapter;
//目标:发动机
interface Motor {
public void drive();
}
//适配者1:电能发动机
class ElectricMotor {
public void electricDrive() {
System.out.println("电能发动机驱动汽车!");
}
}
//适配者2:光能发动机
class OpticalMotor {
public void opticalDrive() {
System.out.println("光能发动机驱动汽车!");
}
}
//电能适配器
class ElectricAdapter implements Motor {
private ElectricMotor emotor;
public ElectricAdapter() {
emotor=new ElectricMotor();
}
public void drive() {
emotor.electricDrive();
}
}
//光能适配器
class OpticalAdapter implements Motor {
private OpticalMotor omotor;
public OpticalAdapter() {
omotor=new OpticalMotor();
}
public void drive() {
omotor.opticalDrive();
}
}
//客户端代码
public class MotorAdapterTest {
public static void main(String[] args) {
System.out.println("适配器模式测试:");
Motor motor=(Motor)ReadXML.getObject();
motor.drive();
}
}
4、缺省形式
缺省就是对于一个具有很多方法的接口,我没只需要其中几个,不想把所有的方法都实现一遍,可以写一个抽象类作为适配器,再去继承该适配器
public interface Adaptee {
void model1();
void model2();
void model3();
void model4();
void model5();
void model6();
void model7();
void model8();
void model9();
void model10();
}
public abstract class Adapter implements Adaptee{
@Override
public void model1() {}
@Override
public void model2() {}
@Override
public void model3() {}
@Override
public void model4() {}
@Override
public void model5() {}
@Override
public void model6() {}
@Override
public void model7() {}
@Override
public void model8() {}
@Override
public void model9() {}
@Override
public void model10() {}
}
public class Target extends Adapter{
@Override
public void model3() {
System.out.println("model3......");
}
@Override
public void model7() {
System.out.println("model7......");
}
}
5、spring中的适配器模式
5.1 SpringMVC
请求处理流程
HandlerAdapter
在 Spring MVC 中使用了适配器模式。HandlerAdapter
主要用于支持不同类型的处理器(如 Controller、HttpRequestHandler 或者 Servlet 等),让它们能够适配统一的请求处理流程。这样,Spring MVC 可以通过一个统一的接口来处理来自各种处理器的请求。在 Spring MVC 的工作流程中,HandlerAdapter
扮演了一个重要角色。以下是其工作原理的简化版:
-
DispatcherServlet
:前端控制器(Front Controller),负责接收所有请求并将其分发给相应的处理程序 -
HandlerMapping
:处理器映射器,立请求URL与处理程序之间的映射关系,默认为RequestMappingHandlerMapping
(根据@Controller注解和@RequestMapping注解来进行URL与处理程序的映射),可以在Spring配置文件(如XML配置文件或Java配置类)中显式地配置所需的HandlerMapping
-
HandlerAdapter
:处理器适配器,通过handlerMapping
获取到对应的处理程序handler(controller)
后,通过所有注册的handlerAdapter
的supports()
方法找到对应的适配器来调用,当存在多个合适的HandlerAdapter时,框架会根据一定规则进行判断和选择
- 用户发起一个 HTTP 请求到 Spring MVC 应用。
-
DispatcherServlet
接收到请求后,首先会调用HandlerMapping
,寻找合适的处理器(Handler)来处理这个请求。 - 找到合适的处理器后,
DispatcherServlet
需要找到一个能够处理这个处理器的HandlerAdapter
。为此,它会遍历所有已注册的HandlerAdapter
,调用它们的supports
方法,检查它们是否支持当前处理器。 - 找到支持当前处理器的
HandlerAdapter
后,DispatcherServlet
会调用该HandlerAdapter
的handle
方法,将请求委托给处理器进行处理。 - 处理器处理完请求后,会返回一个
ModelAndView
对象,DispatcherServlet
会将这个对象传递给适当的ViewResolver
,以解析视图并将响应返回给用户。
我们在
Controller
、Service
、Mapper
中写的业务逻辑,在HandlerAdapter
的处理过程中执行
以下是一个简化的 HandlerAdapter
接口示例:
public interface HandlerAdapter {
boolean supports(Object handler);
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
Spring MVC 提供了一些内置的 HandlerAdapter
实现,如RequestMappingHandlerAdapter
、SimpleControllerHandlerAdapter
、HttpRequestHandlerAdapter
是 Spring MVC 中内置的几个 HandlerAdapter
实现,它们分别用于支持不同类型的处理器。
-
RequestMappingHandlerAdapter
:支持基于注解的处理器,如使用@Controller
和@RequestMapping
注解的处理器方法。这是 Spring MVC 中最常用的处理器类型。 -
SimpleControllerHandlerAdapter
:支持实现org.springframework.web.servlet.mvc.Controller
接口的处理器。这是 Spring MVC 早期版本中的处理器类型,现在已经较少使用。 -
HttpRequestHandlerAdapter
:支持实现org.springframework.web.HttpRequestHandler
接口的处理器。这种类型的处理器主要用于处理静态资源,如图片、样式表等。
举例:
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/{id}")
public String getUserById(@PathVariable("id") Long id, Model model) {
// 执行业务逻辑
return "userDetails";
}
}
在上述例子中有一个controller
,当spring接收到请求时,处理过程为:
假设我们使用了默认的配置和注解驱动。
1、首先,前端控制器(DispatcherServlet)会根据请求的 URL 路径来选择合适的 HandlerMapping。在 Spring MVC 中,默认使用的是 RequestMappingHandlerMapping,它会根据 @RequestMapping 注解以及其他相关注解来确定处理程序(handler)与请求路径之间的映射关系。
2、 对于 UserController 中的 getUserById() 方法,使用了 @GetMapping 注解,并指定了路径为 “/{id}”。因此,当客户端发送 GET 请求到 “/user/{id}” 路径时,RequestMappingHandlerMapping 就会匹配到这个处理程序(handler)。
3、 接下来,在执行处理程序之前,前端控制器还需要选择合适的 HandlerAdapter,并将请求委托给它来执行处理程序。
4、对于标注有 @GetMapping、@PostMapping 等注解的方法,默认情况下会选择 RequestMappingHandlerAdapter 作为主要的 HandlerAdapter。
5、RequestMappingHandlerAdapter 是一个功能强大且灵活的适配器,能够处理包含模型数据、参数绑定、异常处理等复杂情况。
在上述例子中,当通过 RequestMappingHandlerMapping 匹配到 UserController 的 getUserById() 方法后,前端控制器就会选择 RequestMappingHandlerAdapter 来执行这个处理程序,并传递相应的请求参数和模型数据给该方法。
在 Spring MVC 中,前端控制器(DispatcherServlet)会根据请求路径和方法来选择合适的 HandlerAdapter。
选择后,HandlerAdapter 将接收到的请求参数、模型数据等信息传递给相应的处理程序(业务逻辑),并执行该处理程序。
HandlerAdapter 根据具体的处理程序类型来确定调用哪个方法,以及如何将请求数据传递给该方法。
不同类型的处理程序可能有不同的要求和处理方式。 例如,在使用注解配置的方法作为处理程序时,默认情况下会选择 RequestMappingHandlerAdapter。
RequestMappingHandlerAdapter 会根据注解中定义的规则,将请求参数、路径变量、请求体内容等绑定到方法的入参上,并调用该方法执行业务逻辑。它还能够通过模型对象(Model)来向视图传递数据。
可以说 HandlerAdapter 是负责将请求数据传递给我们自己编写的业务逻辑处理程序,并执行其中定义的方法。它是框架与业务代码之间进行通信和协调的重要环节。
自定义handlerAdapter
通常情况下,Spring MVC 默认提供的 HandlerAdapters 是能够满足大多数应用场景的,并且能够处理各种类型的处理程序(handler)。
在某些特殊情况下,可能需要自定义 HandlerAdapter 来满足特定的需求。以下是一些需要自定义 HandlerAdapter 的情况:
需要支持新的处理程序类型:如果你使用了自定义的处理程序类型,而该类型不属于 Spring MVC 默认支持的类型,那么你可以编写自己的 HandlerAdapter 来支持该类型。
特定的请求/响应方式:如果你想要处理一种不常见或非标准的请求/响应方式,例如 WebSocket、SSE(服务器发送事件)等,你可能需要编写一个适配器来处理这些方式。
定制化业务逻辑:如果你有特殊的业务需求,需要在执行业务逻辑之前或之后添加额外的逻辑操作,例如权限校验、日志记录等,你可以编写一个自定义 HandlerAdapter 来扩展框架提供的功能。
性能优化:如果你对性能有极高要求,并希望通过优化执行过程来提升系统性能,可以根据具体场景编写一个更高效的 HandlerAdapter 来替换默认实现。
总之,在需要与 Spring MVC 框架进行更深度集成、满足特定需求或优化性能时,可以考虑自定义 HandlerAdapter。但在大多数情况下,默认提供的 HandlerAdapters 能够满足开发需求。
handlerAdapter的适配器模式
可以看到处理器的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用 Controller 方法,需要调用的时候就得不断地使用 if else 来进行判断是哪一种子类然后执行。那么如果后面要扩展 Controller, 就得修改原来的代码,这样违背了 OCP 原则
下面手写一下handlerAdapter的选择流程
//controller类,我们自己写的逻辑,即handler
public interface Controller {
}
public class AnnotationController implements Controller{
public void doAnnotationHandler() {
System.out.println("annotation...");
}
}
public class HttpController implements Controller{
public void doHttpHandler() {
System.out.println("http...");
}
}
public class SimpleController implements Controller{
public void doSimpleHandler() {
System.out.println("simple...");
}
}
//handlerAdapter类 处理器适配器
//通过handlermapping获取到对应的handler后,再查找对应的处理器适配器调用对应方法
public interface HandlerAdapter {
boolean supports(Object handler);
void handle(Object handler);
}
public class AnnotationHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
// TODO Auto-generated method stub
return (handler instanceof AnnotationController);
}
@Override
public void handle(Object handler) {
// TODO Auto-generated method stub
((AnnotationController)handler).doAnnotationHandler();
}
}
public class HttpHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
// TODO Auto-generated method stub
return (handler instanceof HttpController);
}
@Override
public void handle(Object handler) {
// TODO Auto-generated method stub
((HttpController)handler).doHttpHandler();
}
}
public class SimpleHandlerAdapter implements HandlerAdapter{
@Override
public boolean supports(Object handler) {
// TODO Auto-generated method stub
return (handler instanceof SimpleController);
}
@Override
public void handle(Object handler) {
// TODO Auto-generated method stub
((SimpleController)handler).doSimpleHandler();
}
}
//DispatcherServlet类 执行整体逻辑
public class DispatchServlet {
public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
//注内置的处理器适配器,也可以自定义,然后注册到DispatcherServlet类中
public DispatchServlet() {
handlerAdapters.add(new AnnotationHandlerAdapter());
handlerAdapters.add(new HttpHandlerAdapter());
handlerAdapters.add(new SimpleHandlerAdapter());
}
public void doDispatch() {
/*
* 1、这里用来调用handlermapping获取对应的controller(handler)
* springmvc中默认使用的是 RequestMappingHandlerMapping
*/
AnnotationController annotationController = new AnnotationController();
//2、通过controller(handler)选择对应的handlerAdapter
HandlerAdapter handlerAdapter = getHandler(annotationController);
//3、调用对应处理程序(controller的方法),处理请求
handlerAdapter.handle(annotationController);
}
public HandlerAdapter getHandler(Controller controller) {
for (HandlerAdapter handlerAdapter : handlerAdapters) {
if(handlerAdapter.supports(controller)) {
return handlerAdapter;
}
}
return null;
}
}
//客户端
public class Client {
public static void main(String[] args) {
new DispatchServlet().doDispatch();
}
}
自定义适配器
要自定义一个 HandlerAdapter
,你需要实现 org.springframework.web.servlet.HandlerAdapter
接口,并提供对你的自定义处理器的支持。下面是一个简单的自定义 HandlerAdapter
示例:
首先,创建一个自定义处理器:
public class CustomHandler {
public String handleRequest() {
return "Hello, CustomHandler!";
}
}
接着,实现一个自定义的 HandlerAdapter
:
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof CustomHandler;
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
CustomHandler customHandler = (CustomHandler) handler;
String result = customHandler.handleRequest();
return new ModelAndView("customView", "message", result);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
}
要在 Spring MVC 应用中使用这个自定义的 HandlerAdapter
,你需要将其注册到 DispatcherServlet
中。在基于 Java 配置的应用中,你可以这样做:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
protected void addAdapters(List<HandlerAdapter> adapters) {
adapters.add(new CustomHandlerAdapter());
super.addAdapters(adapters);
}
}
这样,你的自定义 HandlerAdapter
就会在 Spring MVC 应用中生效,并能处理 CustomHandler
类型的处理器。
5.2 AOP
在Spring的Aop中,使用Advice(通知)来增强被代理类的功能,Advice的类型有:BeforeAdvice、AfterReturningAdvice、ThreowSadvice。
每种Advice都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。文章来源:https://www.toymoban.com/news/detail-835056.html
各种不同类型的Interceptor,通过适配器统一对外提供接口,如下类图所示:client —> target —> adapter —> interceptor —> advice。最终调用不同的advice来实现被代理类的增强
原理springmvc类似
文章来源地址https://www.toymoban.com/news/detail-835056.html
到了这里,关于设计模式四:适配器模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!