设计模式四:适配器模式

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)后,通过所有注册的handlerAdaptersupports()方法找到对应的适配器来调用,当存在多个合适的HandlerAdapter时,框架会根据一定规则进行判断和选择

  1. 用户发起一个 HTTP 请求到 Spring MVC 应用。
  2. DispatcherServlet 接收到请求后,首先会调用 HandlerMapping,寻找合适的处理器(Handler)来处理这个请求。
  3. 找到合适的处理器后,DispatcherServlet 需要找到一个能够处理这个处理器的 HandlerAdapter。为此,它会遍历所有已注册的 HandlerAdapter,调用它们的 supports 方法,检查它们是否支持当前处理器。
  4. 找到支持当前处理器的 HandlerAdapter 后,DispatcherServlet 会调用该 HandlerAdapterhandle 方法,将请求委托给处理器进行处理。
  5. 处理器处理完请求后,会返回一个 ModelAndView 对象,DispatcherServlet 会将这个对象传递给适当的 ViewResolver,以解析视图并将响应返回给用户。

我们在ControllerServiceMapper中写的业务逻辑,在HandlerAdapter的处理过程中执行

以下是一个简化的 HandlerAdapter 接口示例:

public interface HandlerAdapter {
   
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

Spring MVC 提供了一些内置的 HandlerAdapter 实现,如RequestMappingHandlerAdapterSimpleControllerHandlerAdapterHttpRequestHandlerAdapter 是 Spring MVC 中内置的几个 HandlerAdapter 实现,它们分别用于支持不同类型的处理器。

  1. RequestMappingHandlerAdapter:支持基于注解的处理器,如使用 @Controller@RequestMapping 注解的处理器方法。这是 Spring MVC 中最常用的处理器类型。
  2. SimpleControllerHandlerAdapter:支持实现 org.springframework.web.servlet.mvc.Controller 接口的处理器。这是 Spring MVC 早期版本中的处理器类型,现在已经较少使用。
  3. 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 的情况:

  1. 需要支持新的处理程序类型:如果你使用了自定义的处理程序类型,而该类型不属于 Spring MVC 默认支持的类型,那么你可以编写自己的 HandlerAdapter 来支持该类型。

  2. 特定的请求/响应方式:如果你想要处理一种不常见或非标准的请求/响应方式,例如 WebSocket、SSE(服务器发送事件)等,你可能需要编写一个适配器来处理这些方式。

  3. 定制化业务逻辑:如果你有特殊的业务需求,需要在执行业务逻辑之前或之后添加额外的逻辑操作,例如权限校验、日志记录等,你可以编写一个自定义 HandlerAdapter 来扩展框架提供的功能。

  4. 性能优化:如果你对性能有极高要求,并希望通过优化执行过程来提升系统性能,可以根据具体场景编写一个更高效的 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。

各种不同类型的Interceptor,通过适配器统一对外提供接口,如下类图所示:client —> target —> adapter —> interceptor —> advice。最终调用不同的advice来实现被代理类的增强
原理springmvc类似
在这里插入图片描述

相关推荐

  1. 设计模式(适配器模式)

    2024-02-21 20:22:01       39 阅读
  2. 设计模式适配器模式

    2024-02-21 20:22:01       46 阅读
  3. 设计模式——适配器模式

    2024-02-21 20:22:01       35 阅读
  4. 设计模式-适配器模式

    2024-02-21 20:22:01       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-21 20:22:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-21 20:22:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-21 20:22:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-21 20:22:01       20 阅读

热门阅读

  1. gin源码实战 day2

    2024-02-21 20:22:01       25 阅读
  2. 【LeetCode-139】单词拆分(回溯&动归)

    2024-02-21 20:22:01       31 阅读
  3. vue实现滚动加载

    2024-02-21 20:22:01       30 阅读
  4. 比较两个文本文件是否相等(C语言)

    2024-02-21 20:22:01       25 阅读
  5. MySQL单表查询

    2024-02-21 20:22:01       29 阅读