Java设计模式 -9- 桥接模式(Bridge模式)

2023-11-09

前言


结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下 7 种:

  1. 代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
  2. 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  3. 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。
  4. 装饰(Decorator)模式:动态地给对象增加一些职责,即增加其额外的功能。
  5. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
  6. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
  7. 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

以上 7种结构型模式,除了适配器模式分为类结构型模式和对象结构型模式两种,其他的全部属于对象结构型模式,下面我们会分别、详细地介绍它们的特点、结构与应用。


在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m×n 种,不但对应的子类很多,而且扩展困难。

当然,这样的例子还有很多,如不同颜色和字体的文字、不同品牌和功率的汽车、不同性别和职业的男女、支持不同平台和不同文件格式的媒体播放器等。如果用桥接模式就能很好地解决这些问题。

桥接模式的定义与特点

桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

通过上面的讲解,我们能很好的感觉到桥接模式遵循了里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总结如下:

优点:

  • 抽象与实现分离,扩展能力强
  • 符合开闭原则
  • 符合合成复用原则
  • 其实现细节对客户透明

缺点:

由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。

桥接模式的结构与实现

可以将抽象化部分与实现化部分分开,取消二者的继承关系,改用组合关系。

1. 模式的结构

桥接(Bridge)模式包含以下主要角色。

  1. 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
  2. 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  3. 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
  4. 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

其结构图如下图所示。
在这里插入图片描述

2. 模式的实现

桥接模式的代码如下:

package bridge;

public class BridgeTest {
    public static void main(String[] args) {
        Implementor imple = new ConcreteImplementorA();
        Abstraction abs = new RefinedAbstraction(imple);
        abs.Operation();
    }
}

//实现化角色
interface Implementor {
    public void OperationImpl();
}

//具体实现化角色
class ConcreteImplementorA implements Implementor {
    public void OperationImpl() {
        System.out.println("具体实现化(Concrete Implementor)角色被访问");
    }
}

//抽象化角色
abstract class Abstraction {
    protected Implementor imple;

    protected Abstraction(Implementor imple) {
        this.imple = imple;
    }

    public abstract void Operation();
}

//扩展抽象化角色
class RefinedAbstraction extends Abstraction {
    protected RefinedAbstraction(Implementor imple) {
        super(imple);
    }

    public void Operation() {
        System.out.println("扩展抽象化(Refined Abstraction)角色被访问");
        imple.OperationImpl();
    }
}

程序的运行结果如下:

扩展抽象化(Refined Abstraction)角色被访问
具体实现化(Concrete Implementor)角色被访问

桥接模式的应用实例

【例1】用桥接(Bridge)模式模拟女士皮包的选购。

分析:女士皮包有很多种,可以按用途分、按皮质分、按品牌分、按颜色分、按大小分等,存在多个维度的变化,所以采用桥接模式来实现女士皮包的选购比较合适。

本实例按用途分可选钱包(Wallet)和挎包(HandBag),按颜色分可选黄色(Yellow)和红色(Red)。可以按两个维度定义为颜色类和包类。

颜色类(Color)是一个维度,定义为实现化角色,它有两个具体实现化角色:黄色和红色,通过 getColor() 方法可以选择颜色;包类(Bag)是另一个维度,定义为抽象化角色,它有两个扩展抽象化角色:挎包和钱包,它包含了颜色类对象,通过 getName() 方法可以选择相关颜色的挎包和钱包。

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <className>yellow</className>
    <className>HandBag</className>
</config>

客户类通过 ReadXML 类从 XML 配置文件中获取包信息,并把选到的产品通过窗体显示出现,下图所示是其结构图。
在这里插入图片描述
程序代码如下:

package bridge;

import org.w3c.dom.NodeList;

import javax.swing.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.awt.*;

public class BagManage {
    public static void main(String[] args) {
        Color color;
        Bag bag;
        color = (Color) ReadXML.getObject("color");
        bag = (Bag) ReadXML.getObject("bag");
        bag.setColor(color);
        String name = bag.getName();
        show(name);
    }

    public static void show(String name) {
        JFrame jf = new JFrame("桥接模式测试");
        Container contentPane = jf.getContentPane();
        JPanel p = new JPanel();
        JLabel l = new JLabel(new ImageIcon("src/bridge/" + name + ".jpg"));
        p.setLayout(new GridLayout(1, 1));
        p.setBorder(BorderFactory.createTitledBorder("女士皮包"));
        p.add(l);
        contentPane.add(p, BorderLayout.CENTER);
        jf.pack();
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

//实现化角色:颜色
interface Color {
    String getColor();
}

//具体实现化角色:黄色
class Yellow implements Color {
    public String getColor() {
        return "yellow";
    }
}

//具体实现化角色:红色
class Red implements Color {
    public String getColor() {
        return "red";
    }
}

//抽象化角色:包
abstract class Bag {
    protected Color color;

    public void setColor(Color color) {
        this.color = color;
    }

    public abstract String getName();
}

//扩展抽象化角色:挎包
class HandBag extends Bag {
    public String getName() {
        return color.getColor() + "HandBag";
    }
}

//扩展抽象化角色:钱包
class Wallet extends Bag {
    public String getName() {
        return color.getColor() + "Wallet";
    }
}
}
package bridge;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;

class ReadXML {
    public static Object getObject(String args) {
        try {
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            doc = builder.parse(new File("src/bridge/config.xml"));
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode = null;
            if (args.equals("color")) {
                classNode = nl.item(0).getFirstChild();
            } else if (args.equals("bag")) {
                classNode = nl.item(1).getFirstChild();
            }
            String cName = "bridge." + classNode.getNodeValue();
            Class<?> c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

程序的运行结果如下图所示。
在这里插入图片描述
如果将 XML 配置文件按如下修改:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <className>Red</className>
    <className>Wallet</className>
</config>

则程序的运行结果如图 4 所示。
在这里插入图片描述

桥接模式的应用场景

当一个类内部具备两种或多种变化维度时,使用桥接模式可以解耦这些变化的维度,使高层代码架构稳定。

桥接模式通常适用于以下场景。

  1. 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
  2. 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
  3. 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。

桥接模式的一个常见使用场景就是替换继承。我们知道,继承拥有很多优点,比如,抽象、封装、多态等,父类封装共性,子类实现特性。继承可以很好的实现代码复用(封装)的功能,但这也是继承的一大缺点。

因为父类拥有的方法,子类也会继承得到,无论子类需不需要,这说明继承具备强侵入性(父类代码侵入子类),同时会导致子类臃肿。因此,在设计模式中,有一个原则为优先使用组合/聚合,而不是继承。
在这里插入图片描述
很多时候,我们分不清该使用继承还是组合/聚合或其他方式等,其实可以从现实语义进行思考。因为软件最终还是提供给现实生活中的人使用的,是服务于人类社会的,软件是具备现实场景的。当我们从纯代码角度无法看清问题时,现实角度可能会提供更加开阔的思路。

桥接模式的扩展

在软件开发中,有时桥接(Bridge)模式可与适配器模式联合使用。当桥接(Bridge)模式的实现化角色的接口与现有类的接口不一致时,可以在二者中间定义一个适配器将二者连接起来,其具体结构图如图 5 所示。
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java设计模式 -9- 桥接模式(Bridge模式) 的相关文章

  • Navicat每次连接MySQL都会产生id_cache.db,id_cache.db-wal,id_cache.db-shm的三个文件

    这三个是Navicat连接数据库时产生的如果没有设置存储位置会直接存储在你的根目录下 看着很难受 Navicat中可以设置其存储位置 选中连接 gt 编辑连接 gt 高级 gt 设置位置
  • 安卓高德地图API根据城市名获取对应的经纬度和地理编码

    private void getLatlon String cityName GeocodeSearch geocodeSearch new GeocodeSearch context geocodeSearch setOnGeocodeS
  • 小程序生成二维码图片保存相册并分享到朋友圈

    小程序echarts canvasdrawer实现页面转化图片并保存到相册 场景 小程序测试活动 实现echarts雷达图展示不同的结果 微信头像 二维码 测试结果文字 最终绘制出一张图片用户保存相册 考虑到开发时间及各种坑使用了canva
  • 12.rtl8188驱动移植

    文章目录 问题 我的解决办法 测试验证 问题 最开始用的rtl8188驱动支持的linux内核版本太低了 编译会出现一些错误 这些错误我尝试去解决 但是并没有成功 上网查找了大量的资料最后才知道是内核版本的问题 我的内核版本是4 19 比较
  • 理解zookeeper选举机制

    一 zookeeper集群 配置多个实例共同构成一个集群对外提供服务以达到水平扩展的目的 每个服务器上的数据是相同的 每一个服务器均可以对外提供读和写的服务 这点和redis是相同的 即对客户端来讲每个服务器都是平等的 这篇主要分析lead
  • 解决VMware共享文件夹在Ubuntu 22.04中无法找到的问题

    我的情况是能找到mnt文件夹 但是文件夹内部为空 没有hgfs文件夹 折腾了一晚上 看了好几篇大佬分享的方案 踩了许多坑 最后综合在一起解决了该问题 之后写下这篇文章记录一下我的解决过程 希望能帮助到大家 一 重新安装VMware Tool
  • WPF 多路径动画描绘轨迹生成几何图形动画

    按照描述轨迹做出几何图像 参照此类方式可制作多种动态数学几何图形 代码可以优化 如有错误自行修正 前台
  • homebrew安装报错:curl: Failed to connect to raw.githubusercontent.com port 443 after xxx ms解决办法

    问题描述 国内安装homebrew 默认会报错 curl Failed to connect to raw githubusercontent com port 443 after 75008 ms Operation 解决方法 网上说的一
  • 串口与树莓派通讯:实现硬件连接与数据交互

    树莓派是一款功能强大的单板计算机 它提供了多种接口和通信方式 其中串口通信是一种常用的方式 串口通信可以用于连接树莓派与外部硬件设备 实现数据的收发和控制 本文将介绍如何在树莓派上配置串口 并通过串口实现与外部设备的通讯 1 串口基础知识
  • 蓝桥杯单片机串口-点亮数码管

    串口传输数据的一种简单利用 其中涉及了数码管 选择器等常规外设 通过串口等配置 用电脑通过串口 向板子发送16进制的数据 在通过简单的计算把所要传输的数据显示出来 通过这个例程还可以和更多的外设相连接 例如通过串口设置一个参考值 与AD D
  • NodeJS分别实现token、cookie登录注册鉴权(KOA2)

    源码 https github com NaCl 131 node study git 包 npm install koa npm i nodemon D 保存自动更新 npm i koa router 路由 npm i koa body
  • 设计模式07 之Bridge

    设计模式07 之Bridge 1 单一职责 模式 在软件组件的设计中 如果责任划分的不清晰 使用继承得到的结果往往是随着需求的变化 子类急剧膨胀 同时充斥着重复代码 这时候的关键是划清责任 典型模式 Decorator 装饰模式 Bridg
  • 关于Keil中“ Error: L6200E: Symbol xxx multiply defined ”的报错解决办法

    在写HC硬件I2C驱动OLED过程中发现了这样一个报错 报错信息显示说 有 F6X8 F8X16 Hzk Title 这几个变量 数组 函数 有重复声明 以下提供两种可能的解决方法 程序中确实存在了相同名字的变量 函数 或数组 删除或者更改
  • 微信小程序网络请求报错:request:fail url not in domain list

    报错信息 request fail url not in domain list 根据提示 合法域名校验出错 然后查看相应文档 微信小程序官方要求每个微信小程序需要事先设置一个通讯域名 小程序只可以跟指定的域名与进行网络通信 所以我们需要在
  • mybatis的SqlMapConfig.xml文件无法下载dtd约束问题

    问题如下 解决方案 打开setting 找DTDS 将如下地址加入 http mybatis org dtd mybatis 3 config dtd 完美解决
  • FormData使用方法详解

    https www jianshu com p e984c3619019 FormData的主要用途有两个 1 将form表单元素的name与value进行组合 实现表单数据的序列化 从而减少表单元素的拼接 提高工作效率 2 异步上传文件
  • NUC980开源项目23-终端显示文件路径

    上面是我的微信和QQ群 欢迎新朋友的加入 项目码云地址 国内下载速度快 https gitee com jun626 nuc980 open source project 项目github地址 https github com Jun117
  • 搭建Hexo博客-第4章-绑定自定义域名

    搭建Hexo博客 第4章 绑定自定义域名 搭建Hexo博客 第4章 绑定自定义域名 搭建Hexo博客 第4章 绑定自定义域名 在这一篇文章中 我将会介绍如何给博客绑定你自己的域名 其实绑定域名本应该很简单的 但我当初在这上走了不少弯路 所以
  • 【数据结构--链表】链表中倒数第k个结点

    题目描述 实现思路 1 先遍历链表 算出链表总长度 然后再计算出顺数第几个是对应节点 返回指向该节点的指针即可 2 快慢指针法 fast slow 首先让fast先走k步 然后fast slow同时走 fast走到末尾时 slow走到倒数第

随机推荐

  • Unity中读取Json文件:基于Assets/Resources文件夹

    我好生气 Python JS里面一两行代码能够搞定的Json读取 在Unity中使用C 读取Json文件超多坑 爬出来一个又来一个 主要是JsonUtility FromJson太不给力了 最好的方式是 使用 https github co
  • mysql有to char函数吗_mysql 类似to_char() to_date()函数

    mysql日期和字符相互转换方法 date format date Y m d gt oracle中的to char str to date date Y m d gt oracle中的to date Y 代表4位的年份 y 代表2为的年份
  • bootstrap-table插件数据加载方式

    bootstrap table插件数据加载方式 data url 直接使用data url在table标签中定义 使用load方法加载数据 finishingTask bootstrapTable load data data为json数组
  • 弹出式菜单(下拉菜单)实现——PopupMenu -

    PopupMenu代表弹出式菜单 它会在指定组件上弹出PopupMenu 默认情况下 PopupMenu会显示在该组件的下方或上方 PopupMenu可增加多个菜单项 并可为菜单项增加子菜单 使用PopupMenu创建菜单的步骤非常简单 只
  • 禁用非必需插件,让 IDEA 飞起

    文章首发于个人博客 欢迎访问关注 https www lin2j tech IDEA 为我们提供了众多的插件 但是这些插件并不都是必须的 如果电脑的性能不够强 反而会带来一些不必要的资源消耗 因此这里整理了一些不常用的插件 可以通过禁用它们
  • 在 msys2 中安装软件 vim git gcc等

    下载安装文件 https github com msys2 msys2 installer releases download 2021 11 30 msys2 x86 64 20211130 exe 主页 MSYS2 更新msys2的软件
  • Android ID详解

    Android中的组件需要用一个int类型的值来表示 这个值也就是组件标签中的id属性值 id属性只能接受资源类型的值 也就是必须以 开头的值 例如 id abc id xyz等 如果在 后面使用 表示当修改完某个布局文件并保存后 系统会自
  • [云原生专题-27]:K8S - 问题解决 - The connection to the server localhost:8080 was refused - did you specify

    1 现象 安装K8S mananger后 执行kubectl get nodes始终出错 root k8s master1 sysctl d kubectl get nodes The connection to the server lo
  • C# TreeView 控件的综合使用方法

    1 概述 该篇文章开发使用的语言c 环境visualstudio2010 sql数据库 主要内容包括 1 treeView控件添加根节点 子节点的基本方法 节点的删除 2 把treeView控件的节点数据保存到SQL数据包括中 把数据库数据
  • 弱电流源是怎么实现的,咱们来仿个真

    原文来自公众号 工程师看海 在我们电子电路设计中 有两种电源 一种是电压源 另一种是电流源 相比于电压源 电流源的使用场景稍微少一点 今天 结合仿真 介绍下一种基于运放的微弱电流源基本实现原理 理论计算与仿真验证相结合 写的清晰易懂 保证一
  • oracle clob raw 转换,ORA-22835: 缓冲区对于 CLOB 到 CHAR 转换或 BLOB 到 RAW 转换而言太小...

    报错信息 Tue Jan 06 09 34 24 2015 Errors in file ggs oracle log diag rdbms orayy3 oyy3a trace oyy3a ora 10028532 trc ORA 228
  • FastAPI 返回图像

    记录一下 我在网上找了好久都不太管用 from fastapi import FastAPI from fastapi import FastAPI File UploadFile Response from fastapi respons
  • arduino控制28byj48步进电机

    写了一个arduino控制28byj48步进电机的程序 主要用于下面这种五线四相步进电机 代码 include
  • Jmeter(十一) - 从入门到精通 - JMeter逻辑控制器 - 下篇(详解教程)

    1 简介 Jmeter官网对逻辑控制器的解释是 Logic Controllers determine the order in which Samplers are processed 意思是说 逻辑控制器可以控制采样器 samplers
  • 图像去噪小波算法的GUI实现(Matlab源代码)

    介绍 本文将介绍如何使用Matlab实现一个带有图形用户界面 GUI 的图像去噪小波算法 小波算法是一种常用的图像去噪方法 通过对图像的小波变换和逆变换进行处理 可以有效地减少图像中的噪声 通过GUI界面 用户可以方便地选择输入图像 调整去
  • 开启hyper-v的嵌套虚拟化

    有的时候会用到windows自带的hyper v来测试一些系统 如果安装的虚拟机需要启用虚拟化原来是一件很麻烦的事情 现在有个不错的powershell命令执行一下就好 Set VMProcessor VMName NestedVM Exp
  • 卷积神经网络原理解析

    朋友们 如需转载请标明出处 人工智能AI技术的博客 CSDN博客 python系列教程 人工智能 程序人生领域博主 自动驾驶 智能医疗保健和自助零售这些领域直到最近还被认为是不可能实现的 而计算机视觉已经帮助我们达到了这些事情 如今 拥有自
  • 2023年京东618PLUS超级补贴如何领取?

    2023年京东618PLUS超级补贴如何领取 2023年京东618PLUS超级补贴仅部分活动商品可用 且不同的PLUS超级补贴使用商品范围不同 所选商品是否满足超级补贴使用门槛 以及结算页显示为准 京东618PLUS超级补贴入口 领取后5月
  • VsCode+QT5.14.2安装部署详细教程

    文章目录 一 下载 1 下载 QT https download qt io archive qt 5 14 2 下载 VsCode https code visualstudio com 3 下载 Cmake https cmake or
  • Java设计模式 -9- 桥接模式(Bridge模式)

    Java设计模式 9 桥接模式 Bridge模式 前言 桥接模式的定义与特点 优点 缺点 桥接模式的结构与实现 1 模式的结构 2 模式的实现 桥接模式的应用实例 桥接模式的应用场景 桥接模式的扩展 前言 结构型模式描述如何将类或对象按某种