Java-第十八部分-设计模式-适配器模式和桥接模式

300 阅读5分钟

设计模式全文

适配器模式

  • 不同国家的电源插座不同,通过多功能转接插头进行转换
  • Adapter Pattern,包装器Wrapper结构型模式,将某个类的接口,转成客户端期望的另一个接口的表示,主要目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作

A类方法由于参数或者返回值类型不匹配,不能直接调用B类方法,通过转接器进行调用

  • 主要分三类,类适配器模式对象适配器模式接口适配器模式
  • 工作原理
  1. 将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容
  2. 从用户的角度看不到被适配者,是解耦的
  3. 用户调用适配器转换而来的目标接口方法,适配器再调用被适配者的相关接口方法
  4. 用户的反馈,只是与目标接口交互

类适配器

  • 通过继承src类被适配者,实现dst类接口,完成适配
  • 案例,220V电压要转换成5V电压,给手机充电 demo.png
  • 被适配类
public class Voltage220V {
    public int output220V() {
        int src = 220;
        System.out.println("Voltage220V");
        return src;
    }
}
  • 适配接口
public interface IVoltage5V {
    public int output5V();
}
  • 类适配器,继承220V,实现转换成5V
public class VoltageAdapter extends Voltage220V implements IVoltage5V{
    @Override
    public int output5V() {
        int src = output220V();
        int dest = src / 40;
        return dest;
    }
}
  • 手机使用,只使用5V的电压
public class Phone {
    public void charging(IVoltage5V i) {
        if (i.output5V() == 5) {
            System.out.println("charging");
        } else if (i.output5V() > 5) {
            System.out.println("i.output5V() > 5");
        }
    }
}
  • 缺点,类适配器需要继承被适配类,从被适配类作为起点,进行转换

对象适配器

  • 持有src被适配者的对象实例 demo2.png
  • 通过聚合绑定被适配类
public class ObjectVoltageAdapter implements IVoltage5V{
    private Voltage220V voltage220V;
    //通过构造器传入
    public ObjectVoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }
    @Override
    public int output5V() {
        int dest = 0;
        if (null != voltage220V) {
            int src = voltage220V.output220V();
            System.out.println("ObjectVoltageAdapter");
            dest = src / 40;
        }
        return dest;
    }
}

接口适配器

  • 缺省适配器模式,适用于一个接口不想使用其所有方法
  • 当不需要全部实现接口提供的方法时,设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现空方法 demo3.png
  • 案例结构 demo4.png
  • InterfaceVoltageAdapter
public class InterfaceVoltageAdapter extends VoltagePhone{
    private Voltage220V voltage220V;
    //通过构造器传入
    public InterfaceVoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }
    @Override
    public int output5V() {
        int dest = 0;
        if (null != voltage220V) {
            int src = voltage220V.output220V();
            System.out.println("InterfaceVoltageAdapter");
            dest = src / 40;
        }
        return dest;
    }
}
  • Phone,依赖于IVoltagePhone接口
public class Phone {
    public void charging(IVoltagePhone i) {
        if (i.output5V() == 5) {
            System.out.println("charging");
        } else if (i.output5V() > 5) {
            System.out.println("i.output5V() > 5");
        }
    }
}
  • 使用
Phone phone = new Phone();
phone.charging(new InterfaceVoltageAdapter(new Voltage220V()));

SprintMVC框架源码

  • DispatcherServlet中的doDispatch方法,根据请求拿到映射的handler,就是一个控制器;通过handler,获取一个适配器,不同的handler需要不同的适配器处理
  1. 先拿到request
  2. 得到Handler(controller)
  3. 得到对应的Adapter image.png
  • getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        //遍历所有的handlers
        Iterator var2 = this.handlerAdapters.iterator();
        
        while(var2.hasNext()) {
            HandlerAdapter adapter = (HandlerAdapter)var2.next();
            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");
}
  • 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);
}
  • HandlerAdapter下的具体实现适配器 image.png
  • 拿到适配器后,适配器调用方法,返回ModelAndView image.png
  • 类图关系 demo.png
  • 扩展controller类型的时候,只需要增加一个适配器即可完成扩展,类似手机根据不同的电压输入,产生不同的处理方式

桥接模式

  • 案例,对不同手机类型、不同品牌实现相同的操作
  • Bridge,结构型设计模式,将实现和抽象放在两个不同的类的层次,两个层次可以独立改变
  • 基于类的最小设计原则,修改代码时,尽量少增加几个类,将抽象和具体分离开来,保持各部分的独立性,和功能扩展
  1. 抽象类,维护了Implementor及它的实现类
  2. ReFinedAbstraction,抽象类的子类
  3. Implementor,行为实现类的接口,桥接类,将实现和抽象连接,抽象类通过Implementor,调用具体的方法
  4. 抽象类和接口是聚合的关系,是调用和被调用的关系
  • 类图,将手机类型和品牌类型分类,通过手机抽象类品牌接口进行桥接 demo.png
  • 品牌接口,手机功能
public interface Brand {
    void call();
    void close();
    void open();
}
  • 品牌实现
public class Vivo implements Brand{
    @Override
    public void call() {
        System.out.println("Vivo Call");
    }
    @Override
    public void close() {
        System.out.println("Vivo close");
    }
    @Override
    public void open() {
        System.out.println("Vivo open");
    }
}
  • 抽象类,将品牌传入手机
public abstract class Phone {
    private Brand brand;
    public Phone(Brand brand) {
        this.brand = brand;
    }
    protected void open() {
        this.brand.open();
    }
    protected void close() {
        this.brand.close();
    }
    protected void call() {
        this.brand.call();
    }
}
  • 抽象的实现类,折叠手机
public class FoldedPhone extends Phone{
    public FoldedPhone(Brand brand) {
        super(brand);
    }
    @Override
    protected void open() {
        super.open();
        System.out.println("FoldedPhone open");
    }
    @Override
    protected void close() {
        super.close();
        System.out.println("FoldedPhone close");
    }
    @Override
    protected void call() {
        super.call();
        System.out.println("FoldedPhone call");
    }
}

JDBC源码

  • mysql包中的Driver
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            //注册驱动,拿到连接
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}
  • registerDriver
public static synchronized void registerDriver(java.sql.Driver driver)
    throws SQLException {

    registerDriver(driver, null);
}
  • Connection的实现类,DriverManager通过getConncetion获取连接 image.png
  • 类图,Connection类似品牌,不同的品牌和数据库,有不同的连接;DriverManager注册不同的驱动,类似使用不同的手机和品牌,获取不同的连接 demo.png

小结

  • 将抽象和实现分离,增加灵活性,助于系统分层
  • 对于系统的高层部分,只需要知道抽象部分和实现部分的接口,其他由具体的业务类实现
  • 桥接模式替代了多层继承方案,减少子类的个数
  • 要求有两个独立变化的维度,适用于不希望使用继承或因为多层级继承导致系统类的个数急剧增加的系统
  1. JDBC驱动程序
  2. 银行转账系统,转账分类网上、柜台、ATM;转账用户普通、银卡、金卡
  3. 消息管理,消息类型即使消息、延时消息;消息分类手机、邮箱、QQ