设计模式之桥接模式

文章目录

  • 一、介绍
  • 二、案例
    • 1. 组件抽象化
    • 2. 桥梁抽象化

一、介绍

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

《Head First 设计模式》:

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

《图解设计模式》:

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

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

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

二、案例

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

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

  • 电池Battery

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

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

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

    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();
        }
    }
    
  • 演示

    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)

    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)

    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)

    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("三星显示屏显示照片...");
        }
    }
    
    

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

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

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

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等,因此我们也需要将手机这个桥梁的角色抽象化。但是如果我们将该桥梁设计成一个接口,由不同的手机品牌实现该接口,那么就可能会导致不同的实现类具有不同参数的构造方法,如此一来,所有品牌手机的功能虽然受到约束(实现类手机接口),但是他们的组成结构却千差万别。如下所示

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)**两个品牌继承该抽象子类。

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("小米手机实例化");
    }
}

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

下面我们进行代码测试

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();
}

在这里插入图片描述

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



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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/96076.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TensorFlow-slim包进行图像数据集分类---具体流程

TensorFlow中slim包的具体用法 1、训练脚本文件(该文件包含数据下载打包、模型训练,模型评估流程)3、模型训练1、数据集相关模块:2、设置网络模型模块3、数据预处理模块4、定义损失loss5、定义优化器模块 本次使用的TensorFlow版本…

web自动化框架:selenium学习使用操作大全(Python版)

目录 一、浏览器驱动下载二、selenium-python安装(打开网站、操作元素)三、网页解析(HTML、xpath)四、selenium基本操作1、元素定位八种方法2、元素动态定位3、iframe切换4、填充表单_填充文本框5、填充表单_单选按钮6、填充表单_…

RT-Thread在STM32硬件I2C的踩坑记录

RT-Thread在STM32硬件I2C的踩坑记录 0.前言一、软硬件I2C区别二、RT Thread中的I2C驱动三、尝试适配硬件I2C四、i2c-bit-ops操作函数替换五、Attention Please!六、总结 参考文章: 1.将硬件I2C巧妙地将“嫁接”到RTT原生的模拟I2C驱动框架 2.基于STM32F4平台的硬件I…

java八股文面试[多线程]——Synchronized的底层实现原理

笔试:画出Synchronized 线程状态流转实现原理图 synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized 翻译为中文的意思是同步,也称之为”同步锁“。 synchronized的作用是保证在同一时刻, 被修饰的代码块或方…

16.CSS菜单悬停特效

效果 源码 <!DOCTYPE html> <html> <head> <title>Creative Menu Item Hover Effects</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body><section><…

(详解)数据结构-----------栈与队列 c语言实现

本章将会详细讲解以下知识点&#xff1a; 目录 一&#xff1a;栈 1&#xff1a;栈的定义&#xff0c;栈的特点 2&#xff1a;用什么结构来实现栈与原因的分析? 3: (超详解)栈的常用接口并且附上测试用例 二:队列 1:队列的定义&#xff0c;队列的特点 2&#xff1a;用什么结…

【ArcGIS微课1000例】0073:ArcGIS探索性回归分析案例

一、探索性回归工具简介 “探索性回归”工具会对输入的候选解释变量的所有可能组合进行评估,以便根据用户所指定的指标来查找能够最好地对因变量做出解释的 OLS 模型。 给定一组候选解释变量,找出正确指定的 OLS 模型: 用法: 工具还会生成一个可选表,该表包括所有满足…

Mybatis1.4 多条件查询

1.4 多条件查询 1.4.1 编写接口方法1.4.2 编写SQL语句1.4.3 编写测试方法1.4.4 动态SQL 我们经常会遇到如上图所示的多条件查询&#xff0c;将多条件查询的结果展示在下方的数据列表中。而我们做这个功能需要分析最终的SQL语句应该是什么样&#xff0c;思考两个问题 条件表达式…

SpringBoot整合JUnit、MyBatis、SSM

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 SpringBoot整合 一、SpringBoot整合JUnit二、Spri…

无人机甚高频无线电中继通讯U-ATC118

简介 甚高频无线电中继通讯系统使用经过适航认证的机载电台连接数字网络传输模块&#xff0c;通过网络远程控制无缝实现无人机操作员与塔台直接语音通话。无人机操作员可以从地面控制站远程操作机载电台进行频率切换、静噪开关、PTT按钮&#xff0c;电台虚拟面板与真实面板布局…

小程序数据导出文件

小程序josn数据生成excel文件 先从下载传送门将xlsx.mini.min.js拷贝下来&#xff0c;新建xlsx.js文件放入小程序项目文件夹下。 const XLSX require(./xlsx)//在需要用的页面中引入// 定义导出 Excel 报表的方法exportData() {const that thislet newData [{time:2021,val…

【Seata】00 - Seata Server 部署(Windows、Docker 基于 Jpom)

文章目录 前言参考目录版本说明Windows 部署 seata-server1&#xff1a;下载压缩包2&#xff1a;文件存储模式3&#xff1a;db 存储模式3.1&#xff1a;建表3.2&#xff1a;修改配置文件3.3&#xff1a;启动脚本4&#xff1a;源码部署 Docker 部署 seata-server &#xff08;基…

程序员必须掌握哪些算法?

一个程序员一生中可能会邂逅各种各样的算法&#xff0c;但总有那么几种&#xff0c;是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓&#xff01;”算法吧~ 文章目录 一、程序员必须掌握哪些算法&#xff1f;二&#xff1a;常见算法介绍…

flutter高德地图大头针

1、效果图 2、pub get #地图定位 amap_flutter_map: ^3.0.0 amap_flutter_location: ^3.0.0 3、上代码 import dart:async; import dart:io;import package:amap_flutter_location/amap_flutter_location.dart; import package:amap_flutter_location/amap_location_option…

R语言APRIORI关联规则、K-MEANS均值聚类分析中药专利复方治疗用药规律网络可视化...

全文链接&#xff1a;http://tecdat.cn/?p30605 应用关联规则、聚类方法等数据挖掘技术分析治疗的中药专利复方组方配伍规律&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 方法检索治疗中药专利复方&#xff0c;排除外用中药及中西药物合用的复方。最近我们…

每天 26,315 美元罚款?交通安全局要求特斯拉提供 Autopilot数据

根据美国国家公路交通安全管理局&#xff08;NHTSA&#xff09;最近的特别命令&#xff0c;特斯拉公司被要求提供关于其自动驾驶功能Autopilot的相关信息。这一命令是继NHTSA于2021年8月启动初步评估后&#xff0c;在2022年6月升级为正式调查的一部分&#xff0c;NHTSA近期对特…

网络安全法+网络安全等级保护

网络安全法 2014年2月&#xff0c;中央网络安全和信息化领导小组成立&#xff0c;习主席当组长 2017年6月1日&#xff0c;网络安全法正式成立 网络安全是国家安全的重要组成部分没有网络安全就没有国家安全&#xff0c;没有信息化就没有现代化 网络安全法21条 网络安全法31条 …

angular抛出 ExpressionChangedAfterItHasBeenCheckedError错误分析

当变更检测完成后又更改了表达式值时&#xff0c;Angular 就会抛出 ExpressionChangedAfterItHasBeenCheckedError 错误。Angular 只会在开发模式下抛出此错误。 在开发模式下&#xff0c;Angular 在每次变更检测运行后都会执行一次附加检查&#xff0c;以确保绑定没有更改。这…

Nginx到底是什么,他能干什么?

目录 Ngnix是什么&#xff0c;它是用来做什么的呢&#xff1f; 一。Nginx简介 二&#xff0c;为什么要用Nginx呢&#xff1f; 二。Nginx应用 1.HTTP代理和反向代理 2.负载均衡 Ngnix是什么&#xff0c;它是用来做什么的呢&#xff1f; 一。Nginx简介 Nginx是enginex的简写&…

Redis——如何解决redis穿透、雪崩、击穿问题

目录 一、查询商品信息的常规代码示例二、缓存击穿2.1、缓存击穿的理解2.2、缓存击穿的解决方案2.3、解决缓存击穿的代码示例 三、缓存雪崩3.1、缓存雪崩的理解3.2、缓存雪崩的解决方案3.2.1、缓存集中过期的情况3.2.2、缓存服务器宕机的情况3.2.3、缓存服务器断电的情况 3.3、…