Java教程

适配器模式(实例+框架源码分析)

本文主要是介绍适配器模式(实例+框架源码分析),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 介绍
    • 1.类适配器模式
  • 演示
    • 2.对象适配器模式
    • 3.接口适配器模式
  • 在源码中应用
  • 总结

介绍

适配器模式是两个不兼容接口间的桥梁,属于结构型模式。适配器模式分为三类,类适配器模式,对象适配器模式,接口适配器模式。我们生活中有很多适配器模式的例子,例如我们给手机充电,家庭电压是220V直流,手机的电压是5V交流,但是我们依然可以直接给手机充电,就是因为充电器充当了适配器的角色。

1.类适配器模式

演示

例子:把220V直流适配成5V交流。
类图:
在这里插入图片描述

Voltage220V类

package com.jc.adapter.classadapter;

/**
 * @program: 设计模式
 * @description:被适配者
 * @author: Mr.Wang
 * @create: 2021-06-16 20:03
 **/
public class Voltage220V {

    public int output220V() {

        int src = 220;

        return src;
    }
}

Voltage5V接口

package com.jc.adapter.classadapter;

/**
 * 目标接口
 */
public interface Voltage5V {
    int output5V();
}

VoltageApdapter类

package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description: 适配器
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:05
**/
public class VoltageAdapter extends Voltage220V implements Voltage5V {
    @Override
    public int output5V() {
        int src = output220V();

        src = src / 44;
        System.out.println("220V已经适配成5V啦!可以充电啦!");
        return src;
    }
}

Phone类

package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:06
**/
public class Phone {
    //充电
    public void charging(Voltage5V voltage5V){

        if (voltage5V.output5V() == 5){
            System.out.println("电压为5V~可以充电");
        }else if(voltage5V.output5V() > 5){
            System.out.println("电压大于5V~不可以充电!");
        }
    }
}

Client

package com.jc.adapter.classadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:08
**/
public class Client {
    public static void main(String[] args) {
        System.out.println("========类适配器模式=========");
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());
//        ========类适配器模式=========
//        220V已经适配成5V啦!可以充电啦!
//        电压为5V~可以充电
    }
}

java是单继承模式,这里适配器继承了220V直流,实现了5V交流接口,接口可以是很多个,但是只能继承一个。
我们继承220V直流的目的时什么?
就是想用他里边的output220V这个方法,然后通过一顿操作将他改成5V直流。根据合成符用原则,如果B类仅仅想使用A类中的方法,我们尽量使用组合和聚合的方式,而不是通过继承。继承带来的后果就是:侵入性,不够灵活,高耦合。
所以我们能用组合和聚合就不要使用继承。
所以我们引出对象适配器模式

2.对象适配器模式

我们只需要把220V直流那个类聚合到适配器类里边就ok了。
类图
在这里插入图片描述
新的适配器类

package com.jc.adapter.objectadapter;

/**
* @program: 设计模式
*
* @description: 适配器
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:05
**/
public class VoltageAdapter implements Voltage5V {
	//聚合进来
    Voltage220V voltage220V;

    public VoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public int output5V() {
        int src = voltage220V.output220V();

        src = src / 44;
        System.out.println("220V已经适配成5V啦!可以充电啦!");

        return src;
    }
}

Client

package com.jc.adapter.objectadapter;

import jdk.internal.dynalink.beans.StaticClass;

import java.util.*;

/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-16 20:08
**/
public class Client {
    public static void main(String[] args) {
        System.out.println("========对象适配器模式=========");
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter(new Voltage220V()));
//        ========对象适配器模式=========
//        220V已经适配成5V啦!可以充电啦!
//        电压为5V~可以充电
    }
}

依然可以实现相同效果,相比于类适配器更加灵活,耦合性低

3.接口适配器模式

1.接口适配器模式又被称为 缺省适配器模式
2.当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求

类图

这里是引用

Interface4

package com.jc.adapter.interfaceadapter;

public interface Interface4 {
    void m1();
    void m2();
    void m3();
    void m4();
    void m5();
}

AbstractAdapter

package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:54
**/
public abstract class AbstractAdapter implements Interface4 {
    @Override
    public void m1() {

    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }

    @Override
    public void m5() {

    }
}

ConcreteAdapter1

package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:59
**/
public class ConcreteAdapter1 extends AbstractAdapter {
    @Override
    public void m1() {
        System.out.println("第一个适配器:我要用m1 所以实现了m1");
    }
    public ConcreteAdapter1(){
        System.out.println("=====我是第一个适配器====我只实现了m1,m3");
    }

    @Override
    public void m3() {
        System.out.println("第一个适配器:我要用m3 所以实现了m3");
    }
}

ConcreteAdapter2

package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:59
**/
public class ConcreteAdapter2 extends AbstractAdapter {


    public ConcreteAdapter2(){
        System.out.println("=====我是第二个适配器====我只实现了m2,m4");
    }
    @Override
    public void m2() {
        System.out.println("第二个适配器:我要用m2 所以实现了m2");
    }

    @Override
    public void m4() {
        System.out.println("第二个适配器:我要用m4 所以实现了m4");
    }
}

Client

package com.jc.adapter.interfaceadapter;/**
* @program: 设计模式
*
* @description: 
*
* @author: Mr.Wang
*
* @create: 2021-06-17 21:54
**/
public class Client {
    public static void main(String[] args) {
        //第一个适配器
        AbstractAdapter adapter1 = new ConcreteAdapter1();
        adapter1.m1();
        adapter1.m3();

        //第二个适配器
        AbstractAdapter adapter2 = new ConcreteAdapter2();
        adapter2.m2();
        adapter2.m4();
//        =====我是第一个适配器====我只实现了m1,m3
//        第一个适配器:我要用m1 所以实现了m1
//        第一个适配器:我要用m3 所以实现了m3
//        =====我是第二个适配器====我只实现了m2,m4
//        第二个适配器:我要用m2 所以实现了m2
//        第二个适配器:我要用m4 所以实现了m4
    }
}

通过打印结果我们实现了自己想要的适配器,并实现了自己的操作。

在源码中应用

1.HttpServlet继承GenericServlet,GenericServlet空实现于javax.servlet.Servlet
在这里插入图片描述
2.在springMVC框架中的应用

这里是引用
HandlerAdapter

public interface HandlerAdapter {
    boolean supports(Object var1);
    @Nullable
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    long getLastModified(HttpServletRequest var1, Object var2);
}

HttpRequestHandlerAdapter (其中一个具体的适配器)

public class HttpRequestHandlerAdapter implements HandlerAdapter {
    public HttpRequestHandlerAdapter() {
    }

    public boolean supports(Object handler) {
        return handler instanceof HttpRequestHandler;
    }

    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ((HttpRequestHandler)handler).handleRequest(request, response);
        return null;
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
    }
}

如何应用的?

DispatchServlet中的doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     
        //根据HandlerMapping获取对应的Handler(Controller)
        mappedHandler = this.getHandler(processedRequest);
        //没有根据映射拿到Handler的话报错。
         if (mappedHandler == null) {
               this.noHandlerFound(processedRequest, response);
               return;
           }
		//从handlerAdapters选择一个支持具体的Hander的适配器
	   HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
     
             
		//根据适配器进行处理,然后返回结果.
	  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	}

getHandlerAdapter方法

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
    	//遍历handlerAdapters选择合适的HandlerAdapter 
        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、将目标类和适配者类解耦,(譬如上边的,将DispatchServlet和具体的适配器解耦)
2、增加了类的透明性和复用性将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性
3、灵活性和扩展性都非常好,符合开闭原则

不好:
适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂
降低代码可读性,过多使用适配器会使系统代码变得很难懂

这篇关于适配器模式(实例+框架源码分析)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!