0
点赞
收藏
分享

微信扫一扫

通过玩游戏学会AWS

兮城 2024-02-21 阅读 24

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,以解析视图并将响应返回给用户。

以下是一个简化的 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 来执行这个处理程序,并传递相应的请求参数和模型数据给该方法。

自定义handlerAdapter
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类似
在这里插入图片描述

举报

相关推荐

0 条评论