设计模式之桥接模式

文章目录

一、介绍

桥接模式,属于结构型设计模式 。通过提供抽象与实现之间的桥接结构 ,把抽象化实现化解耦,使得二者可以独立变化。

《Head First 设计模式》:

将抽象和实现放在两个不同的类层次中,使它们可以独立地变化。

《图解设计模式》:

将类的功能层次结构和实现层次结构相分离,使二者能够独立地变化,并在两者之间搭建桥梁,实现桥接。

从专业术语对交接模式的解释来看,总是让人似懂非懂,即使懂了,从代码上实现又让人无法捉摸。典型的每个字都认识,连在一起就不懂了

下面我们先通过一个简单的例子来演示一下桥接的结构是什么样的,然后对其进行改造,最终实现桥接模式

二、案例

我们假设一部手机有三个重要部件:电池(Battery)摄像头(Camera)屏幕(Screen)。当我们拍摄一张高清照片时,需要充足的电量、高像素的摄像头、高分辨率的屏幕。

于是我们可以通过下面的代码完成拍照动作:

  • 电池Battery

    java 复制代码
    public class Battery {
        public Battery() {
            System.out.println("充足电量的电池");
        }
        
        public void electric() {
            System.out.println("电池供电...");
        }
    }
  • 摄像头Camera

    java 复制代码
    public class Camera {
        public Camera() {
            System.out.println("高清像素的摄像头");
        }
        
        public void catchImg() {
            System.out.println("摄像头捕获图像...");
        }
    }
  • 屏幕Screen

    java 复制代码
    public class Screen {
        public Screen() {
            System.out.println("高分辨率的屏幕");
        }
        
        public void show() {
            System.out.println("屏幕显示照片...");
        }
    }
  • 手机Phone

    java 复制代码
    public class Phone {
        private Battery battery;
        private Camera camera;
        private Screen screen;
    
        public Phone(Battery battery, Camera camera, Screen screen) {
            this.battery = battery;
            this.camera = camera;
            this.screen = screen;
        }
    
        public void takePic() {
            System.out.println("手机拍照开始...");
            // 电池供电
            battery.electric();
            // 摄像头捕获图像
            camera.catchImg();
            // 屏幕显示照片
            screen.show();
        }
    }
  • 演示

    java 复制代码
    public static void main(String[] args) {
        Battery battery = new Battery();
        Camera camera = new Camera();
        Screen screen = new Screen();
    
        Phone phone = new Phone(battery, camera, screen);
        phone.takePic();
    }
  • 结果输出

从该案例中可以看出,电池、摄像头、屏幕这三个组件是相互独立的,各自干各自的活,通过手机将他们连接起来就可以进行拍照,这时手机就表现为桥梁的角色。通过桥梁,三个组件相互独立。

1. 组件抽象化

在实际现实中,无论是电池、摄像头、还是屏幕,他们都有各自的品牌厂商,因此我们需要将他们抽象化。如电池有南孚和山羊;摄像头有索尼和徕卡;屏幕有三星和京东方。

所有我们需要做出修改:新建电池、摄像头、屏幕的抽象类;再分别按照品牌厂商对这些抽象类进行实现。

  • 电池抽象类Battery ,及其实现类:南孚电池(NanFu)山羊电池(Sheep)

    java 复制代码
    public interface Battery {
    
        void electric();
    }
    
    public class NanFu implements Battery {
        public NanFu() {
            System.out.println("南孚电池实例化");
        }
    
        @Override
        public void electric() {
            System.out.println("南孚电池正在供电...");
        }
    }
    
    public class Sheep implements Battery {
        public Sheep() {
            System.out.println("山羊电池实例化");
        }
    
        @Override
        public void electric() {
            System.out.println("山羊电池正在供电...");
        }
    }
  • 摄像头抽象类Camera ,及其实现类:徕卡摄像头(Laika)索尼摄像头(Sony)

    java 复制代码
    public interface Camera {
    
        void catchImg();
    }
    
    public class Laika implements Camera {
        public Laika() {
            System.out.println("徕卡摄像头实例化");
        }
    
        @Override
        public void catchImg() {
            System.out.println("徕卡摄像头捕获图像...");
        }
    }
    
    public class Sony implements Camera {
        public Sony() {
            System.out.println("索尼摄像头实例化");
        }
    
        @Override
        public void catchImg() {
            System.out.println("索尼摄像头捕获图像...");
        }
    }
  • 屏幕抽象类Screen ,及其实现类:京东方显示屏(JingDongFang)三星显示屏(SanXing)

    java 复制代码
    public interface Screen {
    
        void show();
    }
    
    public class JingDongFang implements Screen {
        public JingDongFang() {
            System.out.println("京东方显示屏实例化");
        }
    
        @Override
        public void show() {
            System.out.println("京东方显示屏显示照片...");
        }
    }
    
    public class SanXing implements Screen {
        public SanXing() {
            System.out.println("三星显示屏实例化");
        }
    
        @Override
        public void show() {
            System.out.println("三星显示屏显示照片...");
        }
    }

这样一来,手机的构造方法的参数就由原来的具体实现类变成了抽象类。

java 复制代码
public Phone(Battery battery, Camera camera, Screen screen) {
    this.battery = battery;
    this.camera = camera;
    this.screen = screen;
}

该构造方法参数的实际类型由调用方创建的实例为准。

java 复制代码
public static void main(String[] args) {
    // 使用南孚电池
    Battery battery = new NanFu();
    // 索尼相机
    Camera camera = new Sony();
    // 京东方显示屏
    Screen screen = new JingDongFang();

    Phone phone = new Phone(battery, camera, screen);
    phone.takePic();
}

输出如下

2. 桥梁抽象化

其实不仅电池、摄像头、屏幕有自己的品牌厂商,手机也不例外,如华为、oppo、vivo等,因此我们也需要将手机这个桥梁的角色抽象化。但是如果我们将该桥梁设计成一个接口,由不同的手机品牌实现该接口,那么就可能会导致不同的实现类具有不同参数的构造方法,如此一来,所有品牌手机的功能虽然受到约束(实现类手机接口),但是他们的组成结构却千差万别。如下所示

java 复制代码
public interface MyPhone {
    /**
     * 拍照
     */
    void takePic();
    /**
     * 通话
     */
    void call();

    /**
     * 微信聊天
     */
    void wechat();
}

public class Oppo implements MyPhone{

    private ComponentA componentA;
    private ComponentB componentB;

    public Oppo(ComponentA componentA, ComponentB componentB) {
        this.componentA = componentA;
        this.componentB = componentB;
    }

    @Override
    public void takePic() {
        // 照相
    }

    @Override
    public void call() {
        // 打电话
    }

    @Override
    public void wechat() {
        // 聊微信
    }
}

public class Vivo implements MyPhone{

    private ComponentC componentC;
    private ComponentD componentD;

    public Oppo(ComponentC componentC, ComponentD componentD) {
        this.componentC = componentC;
        this.componentD = componentD;
    }

    @Override
    public void takePic() {
        // 照相
    }

    @Override
    public void call() {
        // 打电话
    }

    @Override
    public void wechat() {
        // 聊微信
    }
}

从上面的代码来看,oppo和vivo虽然实现了**手机(MyPhone)**定义的所有功能,但是却乱七八糟的,oppo手机内部组件是ComponentAComponentB,vivo手机内部组件却是ComponentCComponentD。这样的话手机行业岂不乱套了。

所以我们对桥梁的抽象化不应采用接口,而是抽象类。

使用抽象类有一个好处是,可以使所有子类拥有相同的内部属性,而且对所有子类的构造方法也做出了约束

如下所示,我们将手机抽象化一个手机接口(Phone)来定义各个功能,再通过一个 抽象子类(AbstractPhone)实现手机接口定义的功能,并规范构造方法,由华为(HuaWei)、**小米(XiaoMi)**两个品牌继承该抽象子类。

java 复制代码
public interface Phone {
    /**
     * 拍照
     */
    void takePic();
}

public abstract class AbstractPhone implements Phone {
    private Battery battery;
    private Camera camera;
    private Screen screen;

    public AbstractPhone(Battery battery, Camera camera, Screen screen) {
        this.battery = battery;
        this.camera = camera;
        this.screen = screen;
    }

    @Override
    public void takePic() {
        System.out.println("手机拍照开始...");
        // 电池供电
        battery.electric();
        // 摄像头捕获图像
        camera.catchImg();
        // 屏幕显示照片
        screen.show();
    }
}

public class HuaWei extends AbstractPhone {

    public HuaWei(Battery battery, Camera camera, Screen screen) {
        super(battery, camera, screen);
        System.out.println("华为手机实例化");
    }
}

public class XiaoMi extends AbstractPhone {
    public XiaoMi(Battery battery, Camera camera, Screen screen) {
        super(battery, camera, screen);
        System.out.println("小米手机实例化");
    }
}

通过接口(定义功能)抽象子类(桥梁)、**实现类(实现功能)**的方式,就是交接设计模式的实现。

下面我们进行代码测试

java 复制代码
public static void main(String[] args) {
    Battery battery = new NanFu();
    Camera camera = new Sony();
    Screen screen = new JingDongFang();

    // 华为将南孚电池、索尼相机、京东方显示屏桥接起来形成一部手机
    Phone phone = new HuaWei(battery, camera, screen);
    // 使用华为手机拍照
    phone.takePic();
}

以上就是桥接模式的演变过程,希望通过本篇文章的阅读,能使各位朋友对桥接模式有更深入的理解。

纸上得来终觉浅,绝知此事要躬行。

------------------------我是万万岁,我们下期再见------------------------

相关推荐
不是二师兄的八戒12 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生24 分钟前
Easyexcel(2-文件读取)
java·excel
带多刺的玫瑰41 分钟前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
计算机毕设指导61 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study1 小时前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data1 小时前
二叉树oj题解析
java·数据结构
牙牙7052 小时前
Centos7安装Jenkins脚本一键部署
java·servlet·jenkins
paopaokaka_luck2 小时前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
以后不吃煲仔饭2 小时前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师2 小时前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言