05.设计模式之适配器模式

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

什么是适配器

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

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

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

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

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

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

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

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

适配器模式原理图

适配器模式应用场景

1.springmvc多个不同controller实现;

2.API多版本控制;

适用场景

1. 系统需要使用现有的类,而这些类的接口不符合系统的接口。

​ \2. 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

​ 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 [" + 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)

相关代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值