今天看啥  ›  专栏  ›  康小庄

设计模式学习08——适配器模式

康小庄  · 简书  ·  · 2021-06-23 13:54

写在前面

  • 记录学习设计模式的笔记
  • 提高对设计模式的灵活运用

学习地址

https://www.bilibili.com/video/BV1G4411c7N4

https://www.bilibili.com/video/BV1Np4y1z7BU

参考文章

http://c.biancheng.net/view/1317.html

项目源码
https://gitee.com/zhuang-kang/DesignPattern

10,适配器模式

10.1 适配器模式的定义和特点

适配器模式(Adapter)的定义如下: 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高。

该模式的主要优点如下:

  • 客户端通过适配器可以透明地调用目标接口。
  • 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
  • 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
  • 在很多业务场景中符合开闭原则。

其缺点是:

  • 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
  • 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。

10.2 适配器模式的结构与实现

10.2.1 适配器模式的结构

  1. 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  2. 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  3. 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

10.2.2 代码实现

10.2.2.1 类适配器模式

Voltage5V 目标接口

package com.zhuang.adapter.classadapter;

/**
 * @Classname Voltage5V
 * @Description  定义直流电
 * @Date 2021/3/21 14:14
 * @Created by dell
 */

public interface Voltage5V {
    //定义一个标准充电器来实现
    public int output5V();
}

Voltage220V

package com.zhuang.adapter.classadapter;

/**
 * @Classname Voltage220V
 * @Description 创建交流电
 * @Date 2021/3/21 14:13
 * @Created by dell
 */

public class Voltage220V {
    public int output220V() {
        System.out.println("voltage 输出220伏");
        return 220;
    }
}

VoltageAdapter

package com.zhuang.adapter.classadapter;

/**
 * @Classname VoltageAdapter
 * @Description 创建充电器
 * @Date 2021/3/21 14:14
 * @Created by dell
 */

public class VoltageAdapter extends Voltage220V implements Voltage5V {
    @Override
    public int output5V() {
        //获取交流电220V
        int output220V = output220V();
        //转为5V
        int output5V = output220V / 44;
        System.out.println("VoltageAdapter 输出5伏");
        return output5V;
    }
}

Phone

package com.zhuang.adapter.classadapter;

/**
 * @Classname Phone
 * @Description 手机类
 * @Date 2021/3/21 14:15
 * @Created by dell
 */

public class Phone {
    public void charging(Voltage5V voltage5V) {
        if (voltage5V.output5V() == 5) {
            System.out.println("电压5伏,可以充电");
        } else if (voltage5V.output5V() > 5) {
            System.out.println("电压过大,不可以充电");
        }
    }
}

Client

package com.zhuang.adapter.classadapter;

/**
 * @Classname Client
 * @Description  客户端类
 * @Date 2021/3/21 14:15
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        System.out.println("==类适配器==");
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());
    }
}
image

类适配器模式注意事项和细节

  • Java是单继承机制,所以类适配器需要继承适配者(Adaptee,指Voltage220V)类,这点算是一个缺点,除此之外还必须要求目标(Target,指Voltage5V)必须是接口,有一定局限性;
  • 适配者Voltage220V类的方法在适配器VoltageAdapter类中都会暴露出来,也增加了使用的成本。但是由于其继承了适配者Voltage220V类,所以它可以根据需求重写该类的方法,使得适配器VoltageAdapter类的灵活性增强了。

10.2.2.2 对象适配器模式

Voltage5V

package com.zhuang.adapter.objectadapter;

/**
 * @Classname Voltage5V
 * @Description 充电5V
 * @Date 2021/3/21 14:32
 * @Created by dell
 */

public interface Voltage5V {
    //定义一个标准充电器来实现
    public int output5V();
}

Voltage220V

package com.zhuang.adapter.objectadapter;

/**
 * @Classname Voltage220V
 * @Description 输出220V类
 * @Date 2021/3/21 14:32
 * @Created by dell
 */

public class Voltage220V {
    public int output220V() {
        System.out.println("voltage 输出220伏");
        return 220;
    }
}

VoltageAdapter

package com.zhuang.adapter.objectadapter;

/**
 * @Classname VoltageAdapter
 * @Description 适配器类
 * @Date 2021/3/21 14:33
 * @Created by dell
 */

public class VoltageAdapter implements Voltage5V {

    private Voltage220V voltage220V;

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

    @Override
    public int output5V() {
        //获取交流电220V
        int output220V = voltage220V.output220V();
        //转为5V
        int output5V = output220V / 44;
        System.out.println("VoltageAdapter 输出5伏");
        return output5V;
    }
}

Phone

package com.zhuang.adapter.objectadapter;

/**
 * @Classname Phone
 * @Description 手机类
 * @Date 2021/3/21 14:33
 * @Created by dell
 */

public class Phone {
    public void charging(Voltage5V voltage5V) {
        if (voltage5V.output5V() == 5) {
            System.out.println("电压5伏,可以充电");
        } else if (voltage5V.output5V() > 5) {
            System.out.println("电压过大,不可以充电");
        }
    }
}

Client

package com.zhuang.adapter.objectadapter;

/**
 * @Classname Client
 * @Description 对象适配器测试类
 * @Date 2021/3/21 14:33
 * @Created by dell
 */

public class Client {

    public static void main(String[] args) {
        System.out.println("==对象适配器==");
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter(new Voltage220V()));
    }
}
image

对象适配器模式注意事项和细节

  • 对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。

  • 根据合成复用原则,使用组合替代继承, 所以它解决了类适配器中VoltageAdapter必须继承Voltage220V的局限性问题,也不再强制要求Voltage5V必须是接口。使用成本更低,更灵活。因此,对象适配器模式是适配器模式常用的一种。

10.2.2.3 接口适配器模式

Animation

package com.zhuang.adapter.interfaceadapter;

/**
 * @Classname Animation
 * @Description 动画接口
 * @Date 2021/3/21 14:47
 * @Created by dell
 */

public interface Animation {
    public void method1();

    public void method2();

    public void method3();

    public void method4();

    public void method5();
}

AnimationAdapter

package com.zhuang.adapter.interfaceadapter;

/**
 * @Classname AnimationAdapter
 * @Description  接口适配器类
 * @Date 2021/3/21 14:48
 * @Created by dell
 */

public class AnimationAdapter implements Animation {
    //全部都空实现
    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }

    @Override
    public void method4() {

    }

    @Override
    public void method5() {

    }
}

JFrameAnimation

package com.zhuang.adapter.interfaceadapter;

/**
 * @Classname JFrameAnimation
 * @Description 适配器子类
 * @Date 2021/3/21 14:49
 * @Created by dell
 */

public class JFrameAnimation extends AnimationAdapter {
    @Override
    public void method1() {
        System.out.println("method1()被调用了...");
    }

    @Override
    public void method2() {
        System.out.println("method2()被调用了...");
    }
}

Client

package com.zhuang.adapter.interfaceadapter;

/**
 * @Classname Client
 * @Description  客户端类
 * @Date 2021/3/21 14:50
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        JFrameAnimation animation = new JFrameAnimation();
        animation.method1();
        animation.method2();
    }
}
image

10.3 SpringMVC源码解析

Controller

package com.zhuang.adapter.springmvc;

/**
 * @Classname Controller
 * @Description  springmvc的Controller源码
 * @Date 2021/3/21 14:53
 * @Created by dell
 */

//多种Controller实现
public interface Controller {

}

class HttpController implements Controller {
    public void doHttpHandler() {
        System.out.println("http...");
    }
}

class SimpleController implements Controller {
    public void doSimplerHandler() {
        System.out.println("simple...");
    }
}

class AnnotationController implements Controller {
    public void doAnnotationHandler() {
        System.out.println("annotation...");
    }
}

DispatchServlet

package com.zhuang.adapter.springmvc;

import java.util.ArrayList;
import java.util.List;

/**
 * @Classname DispatchServlet
 * @Description  springmvc的DispatchServlet源码
 * @Date 2021/3/21 14:52
 * @Created by dell
 */

public class DispatchServlet {
    public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>();

    public DispatchServlet() {
        handlerAdapters.add(new AnnotationHandlerAdapter());
        handlerAdapters.add(new HttpHandlerAdapter());
        handlerAdapters.add(new SimpleHandlerAdapter());
    }

    public void doDispatch() {

        // 此处模拟SpringMVC从request取handler的对象,
        // 适配器可以获取到希望的Controller
        HttpController controller = new HttpController();
        // AnnotationController controller = new AnnotationController();
        //SimpleController controller = new SimpleController();
        // 得到对应适配器
        HandlerAdapter adapter = getHandler(controller);
        // 通过适配器执行对应的controller对应方法
        adapter.handle(controller);

    }

    public HandlerAdapter getHandler(Controller controller) {
        //遍历:根据得到的controller(handler), 返回对应适配器
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(controller)) {
                return adapter;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        new DispatchServlet().doDispatch(); // http...
    }

}

HandlerAdapter

package com.zhuang.adapter.springmvc;

/**
 * @Classname HandlerAdapter
 * @Description  springmvc的HandlerAdapter源码
 * @Date 2021/3/21 14:53
 * @Created by dell
 */

///定义一个Adapter接口
public interface HandlerAdapter {
    public boolean supports(Object handler);

    public void handle(Object handler);
}

// 多种适配器类

class SimpleHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((SimpleController) handler).doSimplerHandler();
    }

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof SimpleController);
    }

}

class HttpHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((HttpController) handler).doHttpHandler();
    }

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof HttpController);
    }

}

class AnnotationHandlerAdapter implements HandlerAdapter {

    @Override
    public void handle(Object handler) {
        ((AnnotationController) handler).doAnnotationHandler();
    }

    @Override
    public boolean supports(Object handler) {

        return (handler instanceof AnnotationController);
    }
}

image

写在最后

  • 如果我的文章对你有用,请给我点个👍,感谢你😊!
  • 有问题,欢迎在评论区指出!💪



原文地址:访问原文地址
快照地址: 访问文章快照