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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic boolean supports(Object controller) {return controller instanceof RequestHandlerController;}@Overridepublic 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 {@Overridepublic boolean supports(Object controller) {return controller instanceof ImplController;}@Overridepublic 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 {@Overridepublic boolean supports(Object controller) {return controller instanceof AnnotationController;}@Overridepublic 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 {@Overridepublic boolean supports(Object api) {return api instanceof MayiktApiServiceV2;}@Overridepublic 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 {@Overridepublic boolean supports(Object api) {return api instanceof MayiktApiServiceV1;}@Overridepublic void invok(Object api) {MayiktApiServiceV1 mayiktApiServiceV1 = (MayiktApiServiceV1) api;mayiktApiServiceV1.addUser("mayikt", 22);}
}
适配器优缺点
优点
更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
更好的扩展性:在实现适配器功能的时候,可以扩展自己源的行为(增加方法),从而自然地扩展系统的功能。
缺点
会导致系统紊乱:滥用适配器,会让系统变得非常零乱。例如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
[
](https://blog.csdn.net/weixin_44688301/article/details/115748540)
相关代码
05.设计模式之适配器模式相关推荐
- C#设计模式(7)——适配器模式(Adapter Pattern)
一.引言 在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象.那么如果将"将现存的对象" ...
- 乐在其中设计模式(C#) - 适配器模式(Adapter Pattern)
[索引页] [源码下载] 乐在其中设计模式(C#) - 适配器模式(Adapter Pattern) 作者:webabcd 介绍 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本 ...
- 跟JBPM学设计模式之适配器模式
跟JBPM学设计模式之适配器模式 模式简介 适配器模式(Adapter),将一个类的接口转换成客户希望的另一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 说起适配器模式 ...
- python适配器模式角色_Python设计模式之适配器模式原理与用法详解
本文实例讲述了Python设计模式之适配器模式原理与用法.分享给大家供大家参考,具体如下: 适配器模式(Adapter Pattern):将一个类的接口转换成为客户希望的另外一个接口. 下面是一个适配 ...
- 【设计模式】—— 适配器模式Adapter
模式意图 如果已经有了一种类,而需要调用的接口却并不能通过这个类实现.因此,把这个现有的类,经过适配,转换成支持接口的类. 换句话说,就是把一种现有的接口编程另一种可用的接口. 模式结构 [类的适配器 ...
- 设计模式适配器模式_21世纪的设计模式:适配器模式
设计模式适配器模式 这是我的演讲的第三部分," 21世纪的设计模式" . 适配器模式桥接世界. 在一个世界中,我们有一个概念的界面. 在另一个世界,我们有不同的界面. 这两个接口有 ...
- Java面试题:单例设计模式、适配器模式的不同方式
QUESTION:单例设计模式.适配器模式的不同方式? ANSWER: 1.单例设计模式,适配器设计模式 单利设计模式: 在java中,单例模式是指为了保证类在内存中只 ...
- [学习笔记]设计模式[6]-{适配器模式外观模式}
设计原则 最少知识原则:只和你的密友谈话 这个原则的意思是,在系统设计的过程中,不要让太多的类耦合在一起,免得对系统一部分的修改会影响到其他部分.在设计系统之前,应该首先注意对象与对象之间的交互关系, ...
- 适配器模式_21世纪的设计模式:适配器模式
适配器模式 这是我的演讲的第三部分," 21世纪的设计模式" . 适配器模式桥接世界. 在一个世界中,我们有一个概念的界面: 在另一个世界中,我们有不同的界面. 这两个接口有不同的 ...
最新文章
- mxnet安装及NDArray初体验
- iOS进阶之架构设计MVC(1)
- C#生成CHM文件(中级篇)
- 关于Servlet和异步Servlet
- React组件生命周期-正确执行运行阶段的函数
- Linux高频命令汇总,高频Linux命令
- linux下zip分卷z01解压,Linux下解压分包文件zip(zip/z01/z02)
- mysql安装版与mysql解压版议论
- 数学之美:《社交网络》中Facemash算法分析
- mp4+html+ipad无法播放,mp4文件不能在IPAD上播放
- 客流量总是少?是你门店选址出了问题!
- 关于我在刷题时用OJ判题发现的cout相较于printf严重超时的问题
- P3224 [HNOI2012]永无乡 FHQ-Treap 启发式合并
- hook failed (add --no-verify to bypass)
- log4j2:占位符引起的内存泄漏bug
- BufferQueue has been abandoned
- 计算机软件硬件最核心的,计算机硬件系统最核心的是什么,计算机硬件最核心部件...
- 使用keil设置软复位变量不丢失的数据的区域
- Qt 实现的一个生产者消费者模式类
- 广外2023口译(非英专)复习资料以及模考反馈
热门文章
- Flutter中实现视图、功能和样式代码的分离(使用mixin与扩展函数)
- 100款最佳安全工具谱
- PermGen space内存溢出
- Java开发者动手学习深度学习开篇
- Profit Maximization for Viral Marketing in Online Social Networks: Algorithms and Analysis
- 图像处理基础知识系列之五:贝叶斯方法简单梳理
- 【数据挖掘实战】——电力窃漏电用户自动识别(LM神经网络和决策树)
- VMware中Linux的ens33没有IP地址解决办法
- SpringBoot入门案例
- 硬件电路设计之PLL(频率合成器LMX2541)