小言_互联网的博客

设计模式 ~ 适配器模式分析与实战

361人阅读  评论(0)

设计模式系列文章目录导读:

设计模式 ~ 面向对象 6 大设计原则剖析与实战
设计模式 ~ 模板方法模式分析与实战
设计模式 ~ 观察者模式分析与实战
设计模式 ~ 单例模式分析与实战
设计模式 ~ 深入理解建造者模式与实战
设计模式 ~ 工厂模式剖析与实战
设计模式 ~ 适配器模式分析与实战
设计模式 ~ 装饰模式探究
设计模式 ~ 深入理解代理模式
设计模式 ~ 小结

本文主要内容:

  • 1, 适配器模式概述
  • 2, 适配器模式实现
  • 3, 缺省适配模式
  • 4, 适配器模式的实践

适配器模式概述

适配器模式(Adapter Pattern) 又称 变压器模式,它将已有的类包装起来,使之能满足需要的接口,所以有人又将适配器模式称之为 包装(Wrapper)模式

适配器模式的定义:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够一起工作。

适配器模式涉及到以下 3 个角色:

  • 目标(Target)角色

    该角色定义了要转换成的目标接口

  • 源(Adaptee)角色

    需要被转成目标角色的源角色

  • 适配器(Adapter)角色

    该角色是适配器模式的核心,其职责是通过继承组合的方式,将源角色转换为目标角色

适配器模式类图如下所示:

通过上面的类图我们知道,目标角色里的两个方法:process1()process2() 也就是我们最终需要的,但是源角色也就是现已经在系统存在的类只有 process1(),所以需要适配器角色将两者“融合”在一起。“融合”的方式有两种:继承、类关联

适配器模式优点:

  • 适配器模式可以将两个没有任何关系的类在一起运行
  • 提高类的复用度
  • 增强代码的灵活性
  • 提高类的透明性

适配器模式实现

根据上面的类图,我们可以实现一个简易的使用了适配器模式的代码:

目标角色

public interface Target {
    void process1();
    void process2();
}

源角色

public class Adaptee {
    public void process1() {
        System.out.println("处理逻辑1");
    }
}

适配器角色

public class Adapter extends Adaptee implements Target {
    @Override
    public void process2() {
        System.out.println("处理逻辑2");
    }
}

测试类

public class Client {
    public static void main(String[]args){
        Adapter adapter = new Adapter();
        adapter.process1();
        adapter.process2();
    }
}

控制台输出结果:
    处理逻辑1
    处理逻辑2

我们前面提到实现适配器模式有两种方式:一个是通过继承,一个是通过组合的方式。也就是类的适配器模式对象的适配器模式

我们上面的例子是通过继承的方式,所以它属于 类的适配器模式,实现 对象的适配器模式 也很简单:

public class Adapter2 implements Target {

    private Adaptee adaptee;

    public Adapter2(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void process1() {
        adaptee.process1();
    }

    @Override
    public void process2() {
        System.out.println("处理逻辑2");
    }
}

对象的适配器模式 是将 源角色 通过组合的方式引进来,而不是通过继承的方式

缺省适配模式

缺省(Default Adapter)适配模式用来为一个接口提供默认实现

比如,一个接口很多方法,但是客户端只需要一两个方法,如果实现该接口的话,会有很多空方法,这个时候使用 缺省适配模式 就比较合适了

缺省适配模式JDK 中也有许多应用,例如 java.awt.event.WindowListener

public interface WindowListener extends EventListener {

    public void windowOpened(WindowEvent e);

    public void windowClosing(WindowEvent e);

    public void windowClosed(WindowEvent e);

    public void windowIconified(WindowEvent e);

    public void windowDeiconified(WindowEvent e);

    public void windowActivated(WindowEvent e);

    public void windowDeactivated(WindowEvent e);
}

如果需要使用到 WindowListener ,那就必须实现接口里的所有方法,但是有的时候只会用到一到两个方法,所以 JDK 提供了 WindowAdapter

public abstract class WindowAdapter
    implements WindowListener, WindowStateListener, WindowFocusListener
{

    public void windowOpened(WindowEvent e) {}

    public void windowClosing(WindowEvent e) {}

    public void windowClosed(WindowEvent e) {}

    public void windowIconified(WindowEvent e) {}

    public void windowDeiconified(WindowEvent e) {}

    public void windowActivated(WindowEvent e) {}

    public void windowDeactivated(WindowEvent e) {}

    public void windowStateChanged(WindowEvent e) {}

    public void windowGainedFocus(WindowEvent e) {}

    public void windowLostFocus(WindowEvent e) {}
}

WindowAdapter 里面全是空方法,并且该类是抽象的,因为里面没有任何具体的实现,所以不能实例化。这就是典型的使用到了 缺省适配模式

除了 WindowAdapterjava.awt.event 包里还很多类似的 Adapter:

  • MouseAdapter
  • KeyAdapter
  • FocusAdapter
  • ContainerAdapter
  • ComponentAdapter

实践

适配器模式在开发中也经常用到,能够很好的复用代码。

我们的业务主要是针对两个行业:一个是餐饮,一个是零售

两个行业很多业务是可以共用的,但是零售行业也有自己的一些独有的功能

比如针对商品逻辑,零售可以利用餐饮写好的功能,但是零售也有一些特有的功能,所以针对这个业务,会有两个接口,一个是零售的,一个是餐饮的。


// 零售接口(Target角色)
public interface IRetailMenuSource extends ICommonSource {
    void hangUpGoods();
    void weighGoods();
}

//餐饮已经存在的业务(Adaptee角色)
public class CommonRemoteSource implements ICommonSource {
    // 省略具体的逻辑
}

// (Adapter角色)
public class RetailMenuRemoteSource extends CommonRemoteSource implements IRetailMenuSource{
    @Override
    public void hangUpGoods() {
        //...
    }
    
    @Override
    public void weighGoods() {
        //...
    }
}

类图如下所示:

Reference

  • 《Java与模式》
  • 《Java设计模式及实践》
  • 《Java设计模式深入研究》
  • 《设计模式之禅》

下面是我的公众号,干货文章不错过,有需要的可以关注下,有任何问题可以联系我:


转载:https://blog.csdn.net/johnny901114/article/details/100810001
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场