05.深度解析设计模式,适配器模式应用与优化

适配器模式(Adapter Pattern)是一种结构型设计模式,用于使原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式主要解决在某个模块或类需要与其他模块或类协同工作时,而它们的接口不符合要求的情况。
适配器模式主要有两种实现方式:对象适配器模式和类适配器模式。
1. 对象适配器模式:通过创建一个适配器类,该类包含一个目标接口,并在内部持有被适配的类的实例。适配器类的方法调用被适配类的实例的方法,从而将源接口转换为目标接口。
2. 类适配器模式:通过继承实现适配。适配器类继承自被适配的类,并实现目标接口。适配器类的方法调用被适配类的同名方法,从而将源接口转换为目标接口。
适配器模式的主要优点包括:
提高类的透明性:适配器模式可以隐藏被适配类的内部实现细节,使得调用者无需了解被适配类的具体实现。 增强类的复用性:适配器模式可以使得原本不兼容的类可以协同工作,提高类的复用性。 降低系统的耦合度:适配器模式可以降低被适配类与调用者之间的耦合度,提高系统的灵活性。
适配器模式的一个典型应用场景是,当需要将一个已经存在的类库集成到新的系统中时,而该类库的接口不符合新系统的要求。此时,可以创建一个适配

相关内容:

lass="xiangguan" id="content">

1.什么是适配器? 2.适配器设计原理 3.springmvc 、mybatis哪些场景使用到适配器? 4.企业级多api版本如何采用适配器重构

什么是适配器

1.适配器模式是一种结构型设计模式。适配器模式的思想是:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

苹果手机是否可以插入 圆孔耳机,(圆孔)转接头(接入苹果口子)

2.用电器来打个比喻:有一个电器的插头是三脚的,而现有的插座是两孔的,要使插头插上插座,我们需要一个插头转换器,这个转换器即是适配器。

3.适配器模式涉及3个角色:

源(Adaptee):需要被适配的对象或类型,相当于插头。

适配器(Adapter):连接目标和源的中间对象,相当于插头转换器。

目标(Target):期待得到的目标,相当于插座。

适配器模式包括3种形式:类适配器模式、对象适配器模式、接口适配器模式(或又称作缺省适配器模式)。

适配器模式原理图

适配器模式应用场景

1.springmvc多个不同controller实现;

2.API多版本控制;

适用场景

  1. 系统需要使用现有的类,而这些类的接口不符合系统的接口。
  2. 2. 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
  3. 3.类所做的事情相同或相似,但是具有不同接口的时候。

 4.旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。

 5.使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

springmvc适配器原理分析

方式一:@Controller/@RequestMapping

方式二:实现HttpRequestHandler接口

方式三:实现Controller接口

适配器模式就是把一个类的接口替换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

springmvc 定义controller方式

方式一:

 package com.mayikt.controller;
 
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @RestController
 public class MayiktController {
     /**
     * 访问  mayikt
     *
     * @return
     */
     @RequestMapping("/getMayikt")
     public String getMayikt() {
         return "mayikt";
     }
 }

方式二:

 package com.mayikt.controller;
 
 import org.springframework.stereotype.Component;
 import org.springframework.web.HttpRequestHandler;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Component("/mayiktHttpRequestHandler")
 public class MayiktHttpRequestHandler implements HttpRequestHandler {
     @Override
     public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
         PrintWriter writer = httpServletResponse.getWriter();
         writer.print("mayiktHttpRequestHandler");
         writer.close();
     }
 }

方式三:

 package com.mayikt.controller;
 
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.Controller;
 import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Component("/implController")
 public class MayiktImplController implements Controller {
     @Override
     public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
         PrintWriter writer = response.getWriter();
         writer.print("mayikt--MayiktImplController");
         writer.close();
         return null;
     }
 }

springmvc适配器原理分析

源码解读:

1.springmvc接受请求入口 servlet DispatcherServlet

   三种不同方式定义url映射?

用户选择方式2

方式1:

方式2:

方式3:

如何调试源码呢?idea版本

由于Controller的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用Controller方法,需要在代码中写成如下形式

 package com.mayikt.adapter;
 
 import com.mayikt.adapter.impl.AnnotationController;
 import com.mayikt.adapter.impl.ImplController;
 import com.mayikt.adapter.impl.RequestHandlerController;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public class AdapterInvok {
     public static void invok(Controller controller) {
         if (controller instanceof AnnotationController) {
             AnnotationController annotationController = (AnnotationController) controller;
             annotationController.requestMapping();
             return;
         }
         if (controller instanceof ImplController) {
             ImplController implController = (ImplController) controller;
             implController.handleRequest();
         }
         if (controller instanceof RequestHandlerController) {
             RequestHandlerController requestHandlerController = (RequestHandlerController) controller;
             requestHandlerController.requestHandler();
         }
         
     }
 
     public static void main(String args) {
         AdapterInvok.invok(new ImplController());
     }
 }

如果是这样写代码的话, 后期增加了一种controller的实现方式的话,我们就需要在方法中增加一个if else,这种形式就使得代码非常不好维护,并且也违反了设计模式中的开闭原则。

因此SpringMVC中 定义了一个适配器接口,使得每一种controller都对应一个 适配器类,让适配器代替controller执行对应的方法,这样我们在扩展controller的时候,只需要增加一个对应的适配器类就可以了。

 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
       for (HandlerAdapter adapter : this.handlerAdapters) {
          if (adapter.supports(handler)) {
             return adapter;
          }
       }
    }
    throw new ServletException("No adapter for handler : The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
 }

核心组件

1.目标接口(Target):客户端所期待的接口,目标可以使具体的或抽象类, 也可以是接口

2.需要适配的类(Adaptee):需要适配的类或者适配者类

3.适配器(Adapter):通过包装一个需要适配的对象,把原有接口转换成目标接口

模拟springmvc 不同controller实现

目标接口(Target)

 package com.mayikt.adapter.controller;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public interface Controller {
     
 }

需要适配的类(Adaptee)

 package com.mayikt.adapter.controller.impl;
 
 import com.mayikt.adapter.controller.Controller;
 import lombok.extern.slf4j.Slf4j;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Slf4j
 public class AnnotationController implements Controller {
     public String requestMapping() {
         log.info("<使用注解@Controller>");
         return "ok";
     }
 }
 
 package com.mayikt.adapter.controller.impl;
 
 import com.mayikt.adapter.controller.Controller;
 import lombok.extern.slf4j.Slf4j;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Slf4j
 public class ImplController implements Controller {
     public void handleRequest() {
         log.info("<handleRequest>");
     }
 }
 
 package com.mayikt.adapter.controller.impl;
 
 import com.mayikt.adapter.controller.Controller;
 import lombok.extern.slf4j.Slf4j;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Slf4j
 public class RequestHandlerController implements Controller {
     public void requestHandler() {
         log.info("<requestHandler>");
     }
 }

适配器(Adapter)

package com.mayikt.adapter;

/**
* @author songchuanfu
* @qq 1802284273
* 微信:wx-suagcf
*/
public interface HandlerAdapter {

    boolean supports(Object controller);

    /**
     * 调用到具体的方法
     *
     * @param handler
     */
    void handle(Object handler);
}

package com.mayikt.adapter.impl;

import com.mayikt.adapter.HandlerAdapter;
import com.mayikt.adapter.controller.impl.AnnotationController;
import com.mayikt.adapter.controller.impl.RequestHandlerController;

/**
* @author songchuanfu
* @qq 1802284273
* 微信:wx-suagcf
*/
public class RequestHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object controller) {
        return controller instanceof RequestHandlerController;
    }

    @Override
    public void handle(Object handler) {
        RequestHandlerController requestHandlerController = (RequestHandlerController) handler;
        requestHandlerController.requestHandler();
    }
}

package com.mayikt.adapter.impl;

import com.mayikt.adapter.HandlerAdapter;
import com.mayikt.adapter.controller.impl.ImplController;
import com.mayikt.adapter.controller.impl.RequestHandlerController;

/**
* @author songchuanfu
* @qq 1802284273
* 微信:wx-suagcf
*/
public class ImplHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object controller) {
        return controller instanceof ImplController;
    }

    @Override
    public void handle(Object handler) {
        ImplController implController = (ImplController) handler;
        implController.handleRequest();
    }
}

package com.mayikt.adapter.impl;

import com.mayikt.adapter.HandlerAdapter;
import com.mayikt.adapter.controller.impl.AnnotationController;

/**
* @author songchuanfu
* @qq 1802284273
* 微信:wx-suagcf
*/
public class AnnotationHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object controller) {
        return controller instanceof AnnotationController;
    }

    @Override
    public void handle(Object handler) {
        AnnotationController annotationController = (AnnotationController) handler;
        annotationController.requestMapping();
    }
}


package com.mayikt.adapter;

import com.mayikt.adapter.controller.Controller;
import com.mayikt.adapter.controller.impl.AnnotationController;
import com.mayikt.adapter.controller.impl.ImplController;
import com.mayikt.adapter.impl.AnnotationHandlerAdapter;
import com.mayikt.adapter.impl.ImplHandlerAdapter;
import com.mayikt.adapter.impl.RequestHandlerAdapter;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

/**
* @author songchuanfu
* @qq 1802284273
* 微信:wx-suagcf
*/
public class DispatchServlet {
    private List<HandlerAdapter> handlerAdapters = new ArrayList<>();

    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new ImplHandlerAdapter());
        handlerAdapters.add(new RequestHandlerAdapter());
    }

    public void doDispatch() {
        AnnotationController implController = new AnnotationController();
        HandlerAdapter handlerAdapter = getHandler(implController);
        if (handlerAdapter == null) {
            return;
        }
        handlerAdapter.handle(implController);
    }

    public HandlerAdapter getHandler(Controller controller) {
        for (HandlerAdapter handlerAdapter :
                handlerAdapters) {
            if (handlerAdapter.supports(controller)) {
                return handlerAdapter;
            }
        }
        return null;
    }

    public static void main(String args) {
        new DispatchServlet().doDispatch();
    }
}

模拟api多版本控制

企业中编写了开放接口 MayiktServiceV1. addUser(String userName);

企业中编写了开放接口 MayiktServiceV2. addUserJson(User user);

if("1"==v){

MayiktServiceV1. addUser(String userName);

return ;

}

if("2"==v){

MayiktServiceV2. addUserJson(User user);

return ;

}

if("3"==v){

MayiktServiceV2. addUserJson(User user);

return ;

}

 package com.mayikt.adapter2;
 
 import lombok.extern.slf4j.Slf4j;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 
 @Slf4j
 public class MayiktApiServiceV1 {
     public String addUser(String userName, Integer age) {
         log.info("<v1版本>");
         return "ok";
     }
 }
 
 package com.mayikt.adapter2;
 
 import lombok.extern.slf4j.Slf4j;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 @Slf4j
 public class MayiktApiServiceV2 {
     public String addUserObject(MayiktUserEntity mayiktUserEntity) {
         log.info("<v2版本>");
         return "ok";
     }
 }
 
 package com.mayikt.adapter2;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public class MayiktUserEntity {
     private String userName;
     private Integer age;
 
     public MayiktUserEntity(String userName, Integer age) {
         this.userName = userName;
         this.age = age;
     }
 }
 
 package com.mayikt.adapter2;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public interface MayiktApiAdapter {
     boolean supports(Object api);
     void invok(Object api);
 }
 
 package com.mayikt.adapter2.impl;
 
 import com.mayikt.adapter2.MayiktApiAdapter;
 import com.mayikt.adapter2.MayiktApiServiceV1;
 import com.mayikt.adapter2.MayiktApiServiceV2;
 import com.mayikt.adapter2.MayiktUserEntity;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public class ApiV2Adapter implements MayiktApiAdapter {
     @Override
     public boolean supports(Object api) {
         return api instanceof MayiktApiServiceV2;
     }
 
     @Override
     public void invok(Object api) {
         MayiktApiServiceV2 mayiktApiServiceV2 = (MayiktApiServiceV2) api;
         mayiktApiServiceV2.addUserObject(new MayiktUserEntity("mayikt", 22));
     }
 }
 
 package com.mayikt.adapter2.impl;
 
 import com.mayikt.adapter2.MayiktApiAdapter;
 import com.mayikt.adapter2.MayiktApiServiceV1;
 
 /**
 * @author songchuanfu
 * @qq 1802284273
 * 微信:wx-suagcf
 */
 public class ApiV1Adapter implements MayiktApiAdapter {
     @Override
     public boolean supports(Object api) {
         return api instanceof MayiktApiServiceV1;
     }
 
     @Override
     public void invok(Object api) {
         MayiktApiServiceV1 mayiktApiServiceV1 = (MayiktApiServiceV1) api;
         mayiktApiServiceV1.addUser("mayikt", 22);
     }
 }

适配器优缺点

优点

更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。

更好的扩展性:在实现适配器功能的时候,可以扩展自己源的行为(增加方法),从而自然地扩展系统的功能。

缺点

会导致系统紊乱:滥用适配器,会让系统变得非常零乱。例如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

(https://blog.csdn.net/weixin_44688301/article/details/115748540)

相关代码

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章