找回密码
 立即注册
首页 业界区 业界 适配器模式

适配器模式

施婉秀 9 小时前
适配器模式

基本介绍


  • 1.适配器模式(Adapter Pattern)将某个类的接口(方法)转换成客户期望的另一个接口(方法)表示,主要目的是兼容性,让原本因为方法不匹配的,不能一起工作的两个类可以协同工作。别名叫包装器(Wrapper)。
  • 2.适配器模式属于结构模式。
  • 3.主要有三种形式,类适配器模式,对象适配器模式,接口适配器模式。
类适配器模式

介绍

Adapter类,通过继承src类,实现dest接口,完成src -> dest的适配。
应用实例


  • 1.以手机充电为例,充电器本身相当于Adapter类,220V的交流电相当于src(被适配者),我们的dest(目标)是5V直流电。
  • 2.类图
    1.png

代码

案例只是展示这种思想,无实际意义。
  1. public class Voltage220V {
  2.     public int output220V(){
  3.         int voltage = 220;
  4.         System.out.println("电压" + voltage + "V");
  5.         return voltage;
  6.     }
  7. }
  8. public interface Voltage5V {
  9.     public int output5V();
  10. }
  11. public class Adapter extends Voltage220V implements Voltage5V{
  12.     @Override
  13.     public int output5V() {
  14.         int src = this.output220V();
  15.         int dest = src / 44;//转成5v
  16.         return dest;
  17.     }
  18. }
  19. public class Phone {
  20.     public void charging(Voltage5V v){
  21.         if(v.output5V() == 5){
  22.             System.out.println("电压为5V,可以充电");
  23.         }else if(v.output5V() > 5){
  24.             System.out.println("电压大于5V,不能充电");
  25.         }
  26.     }
  27. }
  28. //测试
  29. public class Client {
  30.     public static void main(String[] args) {
  31.         System.out.println("类适配器模式");
  32.         new Phone().charging(new Adapter());
  33.     }
  34. }
复制代码
注意事项和细节


  • 1.Java是单继承机制,所以类适配器需要继承src类这一点是一个缺点,还要求dest必须是接口,有一定局限性。
  • 2.Adapter类,会继承src类的所有方法,增加了使用成本。
  • 3.由于继承了src类,所以它可以根据需求重写src类的方法,使得Adapter类的灵活性增强了。
对象适配器模式

介绍


  • 1.基本思路和类的适配器模式相同,只是将Adapter类做修改,不是继承src类,而是持有src类的实例,解决兼容性的问题。即持有src类,实现dest接口,完成src -> dest的适配。
  • 2.根据合成复用原则,尽量使用关联关系替代继承关系。
  • 3.对象适配器模式是适配器模式常用的一种。
应用实例

用对象适配器模式,完成手机充电案例
  1. public class Voltage220V {
  2.     public int output220V(){
  3.         int voltage = 220;
  4.         System.out.println("输出电压" + voltage + "V");
  5.         return voltage;
  6.     }
  7. }
  8. public interface Voltage5V {
  9.     public int output5V();
  10. }
  11. public class Phone {
  12.     public void charging(Voltage5V v){
  13.         if(v.output5V() == 5){
  14.             System.out.println("电压为5V,可以充电");
  15.         }else if(v.output5V() > 5){
  16.             System.out.println("电压大于5V,不能充电");
  17.         }
  18.     }
  19. }
  20. public class Adapter implements Voltage5V {
  21.     private Voltage220V voltage220V;
  22.     public Adapter(){}
  23.     public Adapter(Voltage220V voltage220V){
  24.         this.voltage220V = voltage220V;
  25.     }
  26.     public void setVoltage220V(Voltage220V voltage220V) {
  27.         this.voltage220V = voltage220V;
  28.     }
  29.     @Override
  30.     public int output5V() {
  31.         int src = voltage220V.output220V();
  32.         int dest = src / 44;
  33.         System.out.println("进行电压适配" + src + "->" + dest);
  34.         return dest;
  35.     }
  36. }
  37. public class Client {
  38.     public static void main(String[] args) {
  39.         System.out.println("对象适配器模式");
  40.         Phone phone = new Phone();
  41.         Adapter adapter = new Adapter(new Voltage220V());
  42.         phone.charging(adapter);
  43.     }
  44. }
复制代码
注意事项和细节


  • 1.对象适配器和类适配器是同一种思想,只是实现方式不同。根据合成复用原则,使用组合代替继承,所以它解决了类适配器必须继承src的局限性问题,也不再要求dest是接口。
  • 2.使用成本更低,更灵活。
接口适配器模式

介绍


  • 1.当不需要全部实现接口提供的方法时,可以设计一个抽象类实现接口,并为该接口中每个方法提供一个默认的实现(空方法),那么该抽象类的子类可以有选择性的重写某些方法。
  • 2.适用于一个接口不想使用其所有方法的情况
  • 3.接口适配器模式,也被称为默认适配器模式。
应用实例


  • 1.Android中的属性动画ValueAnimator类可以通过addListener(AnimatorListener listener)方法添加监听器,常规方法如下右图。
  • 2.不想实现Animator.AnimatorListener接口的全部方法,我们只想监听onAnimationStart 如下 下图写。
    2.png

  • 3.AnimatorListenerAdapter类,就是一个接口适配器,代码如下 右图。
  • 4.AnimatorListener是一个接口。
    3.png

  • 5.程序里的匿名内部类就是AnimatorListener的具体实现类。
    Java中的匿名内部类,类似接口适配器模式。
适配器模式在SpringMVC中的源码分析


  • 1.SpringMVC中的HandlerAdapter,就是用了适配器模式。
  • 2.使用HandlerAdapter的原因分析。Handler(controller,处理器)的类型不同,有多重实现方式,那么调用方式就不是确定的,如果需要直接调用Controller方法,需要调用时,就要使用很多的if else分支语句,进行判断,哪一种子类执行。这样的写法,如果要扩展controller,就要修改原来的代码,违背了ocp。
  • 3.代码分析
  1. //DispatchServlet类中得doDispatch(HttpServletRequest request, HttpServletResponse response)方法 部分源码
  2. HttpServletRequest processedRequest = request;
  3. HandlerExecutionChain mappedHandler = null;//参数定义
  4. // Determine handler for the current request.
  5. mappedHandler = getHandler(processedRequest);//根据请求获取 对应的HandlerExecutionChain
  6. if (mappedHandler == null) {
  7.    noHandlerFound(processedRequest, response);
  8.    return;
  9. }
  10. // Determine handler adapter for the current request.
  11. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//根据handler获取对应的HandlerAdapter
  12. //getHandlerAdapter源码 遍历所有的HandlerAdapter 判断是否支持当前handler,支持返回对应的HandlerAdapter
  13. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  14.                 if (this.handlerAdapters != null) {
  15.                         for (HandlerAdapter ha : this.handlerAdapters) {
  16.                                 if (logger.isTraceEnabled()) {
  17.                                         logger.trace("Testing handler adapter [" + ha + "]");
  18.                                 }
  19.                                 if (ha.supports(handler)) {
  20.                                         return ha;
  21.                                 }
  22.                         }
  23.                 }
  24.                 throw new ServletException("No adapter for handler [" + handler +
  25.                                 "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  26. }
复制代码

  • 4.HandlerAdapter接口中的方法
  1. boolean supports(Object handler);//判断是否支持当前handler
  2. //执行handler
  3. @Nullable
  4. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
  5. long getLastModified(HttpServletRequest request, Object handler);
复制代码

  • 5.HandlerAdapter及其子类
    4.png

  • 6.简单模拟写一下适配器模式,及其对应的controller源码
  1. /**
  2. * @author 长名06
  3. * @version 1.0
  4. * Controller接口
  5. */
  6. public interface Controller {
  7. }
  8. class HttpController implements Controller{
  9.     public void doHttpController(){
  10.         System.out.println("http...");
  11.     }
  12. }
  13. class SimpleController implements Controller{
  14.     public void doSimpleController(){
  15.         System.out.println("simple...");
  16.     }
  17. }
  18. class AnnotationController implements Controller{
  19.     public void doAnnotationController(){
  20.         System.out.println("annotation...");
  21.     }
  22. }
  23. /**
  24. * @author 长名06
  25. * @version 1.0
  26. * 适配器接口
  27. * 一个controller对应一个handlerAdapter
  28. */
  29. public interface HandlerAdapter {
  30.     //判断handler是否是当前适配器对应的controller
  31.     boolean supports(Object handler);
  32.     void handle(Object handler);
  33. }
  34. class HttpHandlerAdapter implements HandlerAdapter{
  35.     @Override
  36.     public boolean supports(Object handler) {
  37.         return (handler instanceof HttpController);
  38.     }
  39.     @Override
  40.     public void handle(Object handler) {
  41.         ((HttpController) handler).doHttpController();
  42.     }
  43. }
  44. class SimpleHandlerAdapter implements HandlerAdapter{
  45.     @Override
  46.     public boolean supports(Object handler) {
  47.         return (handler instanceof SimpleController);
  48.     }
  49.     @Override
  50.     public void handle(Object handler) {
  51.         ((SimpleController) handler).doSimpleController();
  52.     }
  53. }
  54. class AnnotationHandlerAdapter implements HandlerAdapter{
  55.     @Override
  56.     public boolean supports(Object handler) {
  57.         return (handler instanceof AnnotationController);
  58.     }
  59.     @Override
  60.     public void handle(Object handler) {
  61.         ((AnnotationController) handler).doAnnotationController();
  62.     }
  63. }
  64. /**
  65. * @author 长名06
  66. * @version 1.0
  67. * 适配器模式
  68. */
  69. public class Dispatch {
  70.     public static final List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();
  71.     public Dispatch(){
  72.         handlerAdapters.add(new HttpHandlerAdapter());
  73.         handlerAdapters.add(new AnnotationHandlerAdapter());
  74.         handlerAdapters.add(new SimpleHandlerAdapter());
  75.     }
  76.     public void doDispatch(){
  77. //        HttpController controller = new HttpController();
  78. //        SimpleController controller = new SimpleController();
  79.         AnnotationController controller = new AnnotationController();
  80.         HandlerAdapter adapter = getHandler(controller);
  81.         adapter.handle(controller);
  82.     }
  83.     public HandlerAdapter getHandler(Controller controller){
  84.         for(HandlerAdapter ha : this.handlerAdapters){
  85.             if(ha.supports(controller)){
  86.                 return ha;
  87.             }
  88.         }
  89.         return null;
  90.     }
  91.     public static void main(String[] args) {
  92.         new Dispatch().doDispatch();
  93.     }
  94. }
复制代码
注意事项和细节


  • 1.三种形式,按照src以怎样的方式给到Adapter(在Adapter里的形式)命名的
  • 2.类适配器:以类给到,在Adapter里,就是将src当作类,继承;对象适配器:以对象给到 ,在Adapter里,将src作为一个对象持有;接口适配器:以接口给到,在Adapter里,将src作为一个接口,实现。
  • 3.Adapter模式最大的作用就是将原本不兼容的接口融合在一起工作。
  • 4.实际开发中,不一定非要按照这三种要求,重要的是其思想
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册