JS设计模式之桥接模式:搭建跨越维度的通路

news2024/11/18 3:48:34

image.png

引言

在软件开发中,我们经常遇到需要对不同的抽象类进行不同的实现的情况,而传统的对象嵌套并不是一个优雅且可扩展的解决方案,因此这正是桥接模式的用武之地。桥接模式通过将抽象与实现分离,使得它们可以独立变化,从而提供了更好的可扩展性和代码重用性。

在本篇文章中,我们将从桥接模式的基本概念出发,深入剖析其原理和实现方法。我们将学习如何创建抽象类和实现类,并通过桥接类将它们连接起来。同时,我们还将通过实际案例来展示桥接模式的应用,以及它与其他设计模式的关系。

一. 桥接模式的基本概念

1. 什么是桥接模式

桥接模式(Bridge Pattern)是一种重要的结构型设计模式,它主要用于解耦抽象和实现之间的关系,使它们能够独立变化。在 JavaScript 中,桥接模式允许我们将抽象和具体实现部分分离,使它们可以独立进行扩展和演化。

在传统的 JavaScript 开发中,我们通常使用继承来实现抽象和具体实现之间的关系。例如,我们可以定义一个基类,然后通过创建子类来实现不同的具体实现。这种方式存在一些问题,例如子类的扩展会导致类的爆炸性增长,并且难以应对多个维度的变化。

而桥接模式则提供了一种更加灵活和可扩展的解决方案。它通过使用抽象接口和具体实现类之间的桥接,将它们解耦并以独立的方式进行演化。通过桥接模式,我们可以在运行时动态地将抽象和实现连接起来,而无需在编译时进行固定的绑定。

在桥接模式中,抽象类是一个具有抽象方法的类或接口,它定义了抽象部分的接口。具体实现类是实现抽象类的具体类,它实现了抽象部分的具体操作。桥接类充当桥梁,将抽象类和具体实现类连接起来,通过调用具体实现类的方法来实现抽象部分的功能。

2. 桥接模式的核心要素

JavaScript 桥接模式的核心要素包括以下三部分:

  1. 抽象类(或接口):抽象类定义了抽象部分的接口和行为,它是桥接模式中的核心概念。抽象类为实现提供了一个承的基础,它声明了抽象方法和属性,描述了抽象部分的功能。在 JavaScript 中,抽象类可以通过类(class)或者接口(interface)来定义。

  2. 实现类:实现类提供了抽象部分的具体实现。它是抽象类的具体子类,在实现类中实现了抽象类中声明的抽象方法和属性。实现类可以根据需求进行扩展和修改,不会影响到抽象类的设计。在 JavaScript 中,实现类可以是普通的 JavaScript 类。

  3. 桥接类:桥接类充当了抽象类和实现类之间的桥梁,将抽象部分的行为委托给具体实现。桥接类包含一个对实现类的引用,将抽象部分的方法调用委托给实现类。通过桥接类,抽象类和实现类可以独立地变化,它们之间解耦合,使得系统更加灵活和可扩展。

总结:JavaScript 桥接模式的核心要素包括抽象类(或接口)、实现类和桥接类。抽象类定义抽象部分的接口和行为,实现类提供抽象部分的具体实现,桥接类充当抽象类和实现类之间的桥梁,将抽象部分的行为委托给具体实现。这样可以实现抽象和实现的解耦,提供更好的可扩展性和灵活性。

3. UML 类图说明

image.png

  • 抽象部分Abstraction):是一个抽象类或接口,它定义了抽象部分的方法。在JavaScript中,我们使用构造函数或类来代表抽象部分。

  • 扩充抽象部分RefAbstraction):是抽象部分具体实现类。在JavaScript中,我们使用子类来代表扩充抽象部分,它继承了抽象部分并可以扩展额外的功能。

  • 实现部分Implementor):是一个接口或抽象类,它定义了实现部分的方法。在JavaScript中,我们使用对象字面量或构造函数来代表实现部分。

  • 具体实现部分ConcreteImplementor):是实现部分的具体实现类。在JavaScript中,我们使用具体对象或构造函数来代表具体实现部分。

  • 客户端Client):是使用桥接模式的代码部分。在JavaScript中,我们可以在客户端中创建抽象部分和实现部分的对象,并进行组合和调用。

以上是一个简单的桥接模式的用例图解析,通过使用桥接模式,我们可以将抽象部分和实现部分分离,使其可以独立地变化和扩展。

二. 实现桥接模式

步骤 1:定义抽象类(或接口)

首先,创建一个抽象类(或接口),它定义了抽象部分的接口和行为。这个抽象类可以是一个普通的 JavaScript 类,或者使用接口的方式。

// 定义抽象类
class AbstractClass {
  constructor(implementation) {
    this.implementation = implementation;
  }

  performAction() {
    // 委托实现类的具体方法
    this.implementation.action();
  }
}

步骤 2:定义实现类

要实现桥接模式,需要创建一个或多个实现类,它们提供了抽象部分的具体实现。这些实现类可以是普通的 JavaScript 类。

// 定义实现类A
class ConcreteImplementationA {
  action() {
    console.log("ConcreteImplementationA is performing action");
  }
}

// 定义实现类B
class ConcreteImplementationB {
  action() {
    console.log("ConcreteImplementationB is performing action");
  }
}

步骤 3:创建桥接实例

通过将实现类实例传递给抽象类的构造函数,创建一个桥接实例。这样,抽象类引用了具体的实现类。

// 创建桥接实例
const instance1 = new AbstractClass(new ConcreteImplementationA());
instance1.performAction(); // 输出:ConcreteImplementationA is performing action

const instance2 = new AbstractClass(new ConcreteImplementationB());
instance2.performAction(); // 输出:ConcreteImplementationB is performing action

在上面的代码中,我们进行了3个步骤,完整的实现了一个桥接模式的运用。

首先,我们定义了一个抽象类 AbstractClass,它接收一个具体的实现类实例作为参数,并在 performAction 方法中调用实现类的 action 方法。

然后,我们定义了两个具体的实现类 ConcreteImplementationAConcreteImplementationB,它们都实现了 action 方法,并有不同的实现。

最后,我们创建了两个桥接实例 instance1instance2。当调用 performAction 方法时,实际执行的是具体实现类中的 action 方法,输出了不同的结果。

通过这样的实现,我们使用桥接模式将抽象部分和实现部分进行了解耦,可以灵活地改变或扩展实现类的行为,而不会影响到其他部分的代码。

三. 桥接模式的优缺点

优点

  1. 解耦性强:桥接模式能将抽象部分和实现部分相互解耦,使它们可以独立变化。通过将抽象类和实现类分离,可以使它们可以独立进行修改和扩展,不会相互影响。

  2. 扩展性好:由于桥接模式能灵活地将抽象部分和实现部分组合起来,因此在需要新增实现类或抽象部分时,可以在不修改现有代码的情况下进行扩展。

  3. 可复用性高:桥接模式中的抽象类可以通过不同的实现类进行组合,可以更好地复用已有的代码。实现类也可以在不同的抽类中进行复用。

  4. 可以动态切换实现:桥接模式使得可以在运行时动态地切换具体的实现类,而不影响抽象类。这种动态切换可以在一定程度上实现运行时的灵活性和可定制性。

缺点

  1. 增加了系统的复杂性:使用桥接模式会增加一定的类和对象的数量,增加了系统的复杂性,会增加代码的阅读和维护难度。

  2. 引入了间接性:桥接模式通过一层间接来把抽象部分和实现部分连接起来,有时候可能会导致理解和调试困难。

综上所述,桥接模式在将抽象和实现部分相互解耦、提供灵活性和可扩展性方面具有明显的优势。但它也会增加系统的复杂性,并且引入了一层间接性。在具体应用时需要权衡利弊,根据实际需求决定是否使用桥接模式。

四. 应用案例

image.png

图形绘制应用

应用场景:假设有一个图形绘制应用,需要支持不同的图形形状(如矩形、圆形等)和不同的绘制颜色(如红色、蓝色等)的组合。这时可以使用桥接模式来实现。

首先,我们定义图形的抽象类 Shape

class Shape {
  constructor(color) {
    this.color = color;
  }

  draw() {
    console.log(`Drawing a ${this.color.fill()} ${this.constructor.name}`);
  }
}

然后,我们定义具体的图形类,如 RectangleCircle

class Rectangle extends Shape {
  constructor(color) {
    super(color);
  }
}

class Circle extends Shape {
  constructor(color) {
    super(color);
  }
}

接下来,我们定义颜色的抽象类 Color

class Color {
  fill() {
    throw new Error("This method must be overridden");
  }
}

再然后,我们具体的颜色类,如 RedBlue

class Red extends Color {
  fill() {
    return "red";
  }
}

class Blue extends Color {
  fill() {
    return "blue";
  }
}

最后,我们可以通过桥接模式来创建图形,并指定具体的颜色:

const redRectangle = new Rectangle(new Red());
redRectangle.draw(); // 输出:Drawing a red Rectangle

const blueCircle = new Circle(new Blue());
blueCircle.draw(); // 输出:Drawing a blue Circle

在上面的实例中,我们使用桥接模式将图形的抽象部分(Shape)和颜色的抽象部分(Color)分离开来,并通过组合的方式将它们连接起来。

通过定义具体的图形类(RectangleCircle)和具体的颜色类(RedBlue),我们可以根据需要灵活地组合不同的图形和颜色,实现各种绘制组合。

调用图形的 draw 方法,实际上会调用具体的颜色类的 fill 方法,输出相应的绘制信息。

这样,使用桥接模式可以让我们轻松扩展和修改图形的形状和颜色,而不会相互影响。同时,也提高了代码的可复用性和可维护性。

五. 桥接模式的最佳实践

  1. 明确定义抽象部分和实现部分:在设计桥接模式时,首先需要明确抽象部分和实现部分的功能和职责。抽象部分通常是高层模块,定义了抽象方法和属性,而实现部分是低层模块,负责实现具体的功能。

  2. 组合而非继承:桥接模式通常通过组合来连接抽象部分和实现部分,而不是使用继承。这样可以实现抽象部分和实现部分的解耦,同时也更加灵活地扩展和变化。

  3. 通过接口或抽象类定义抽象部分:在 JavaScript 中,可以使用接口或抽象类来定义抽象部分的方法和属性。这可以为具体的实现类提供一个共同的接口,方便统一调用。

  4. 应用适当的设计模式:桥接模式可以与其他设计模式配合使用,以实现更复杂的功能。例如,可以与工厂模式结合,用于创建不同的实现类实例。

  5. 考虑灵活性和可扩展性:桥接模式的优势之一是灵活性和可扩展性。因此,在设计时应该考虑到后续可能的变化和扩展。如需新增抽象部分或实现部分,应该可以轻松添加新的类而不影响现有的代码。

总之,JavaScript 桥接模式的最佳实践是明确定义抽象部分和实现部分、使用组合而不是继承、通过接口或抽象类定义抽象部分、应用适当的设计模式、考虑灵活性和可扩展性,以及合理命名和组织代码。这样能够使得代码结构清晰、可维护性高,并且能够轻松地扩展和修改功能。

总结

在本篇文章中,我们详细解析了 JavaScript 桥接模式的基础和应用,并总结了项目最佳实践。桥接模式通过将抽象部分和实现部分分离,可以让它们分别独立变化,以实现更灵活的扩展和变化。

当你需要设计具有多个不同维度的变化的系统时,桥接模式是一个很好的选择。它可以避免类的指数级增长,并且能够灵活组合不同的抽象和实现。

通过桥接模式,我们可以轻松地组合不同的抽象和实现,满足不同的需求。同时,桥接模式还提供了代码重用和可维护性的好处,使得我们的代码更加整洁和可扩展。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前缀和(5)_和为k的子数组

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 前缀和(5)_和为k的子数组 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1. 题目…

列表控件QListWidget

显示模式 有两种显示模式,列表模式和图标模式 // 获取和设置显示模式 QListView::ViewMode viewMode() const void setViewMode(QListView::ViewMode mode) QListView::ViewMode有两个取值 QListView::ListMode 列表模式 QListView::IconMode 图标模式 交替背…

《银河战星:僵局》风灵月影修改器使用指南,轻松驾驭宇宙战场

在策略射击游戏《银河战星:僵局》中,合理利用风灵月影修改器能极大提升你的游戏体验。 以下是简明操作步骤,助你迅速上手,遨游星际: 1.下载安装: 首先,确保从正规渠道获取风灵月影修改器&…

冒泡排序-C语言

1.问题&#xff1a; 从小到大对10个数进行排序&#xff0c;要求使用冒泡排序实现。 2.解答&#xff1a; 排序规律有两种&#xff1a;一种是“升序”&#xff0c;从小到大&#xff1b;另一种是“降序”&#xff0c;从大到小。 3.代码&#xff1a; #include<stdio.h>//头…

保护您的网络:入侵检测系统 IDS 终极指南

IDS 和 IPS&#xff1a;了解异同-CSDN博客 IDS(入​​侵检测系统) 和 IPS(入​​侵防御系统) 之间的区别-CSDN博客 即便是今天&#xff0c;互联网仍与黑客肆意横行的网络无异。 但不必害怕&#xff01;我们有解决您问题的完美解决方案&#xff1a;入侵检测系统 I DS。 IDS就…

本地打开打包后的dist文件报错的解决方法

出现问题 本地直接打开dist文件夹会报错&#xff0c;报错信息类似于&#xff1a; Access to script at file:///D:/assets/index.9cb0ffcc.js from origin null has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome, ch…

TypeScript基础语法与面对对象

TypeScript 基础语法 TypeScript 与面向对象 面向对象是一种对现实世界理解和抽象的方法。TypeScript 是一种面向对象的编程语言。面向对象主要有两个概念&#xff1a;对象和类 对象&#xff1a;对象是类的一个实例&#xff08;对象不是找个女朋友&#xff09;&#xff0c;有…

【优选算法】(第四篇)

目录 三数之和&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 四数之和&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 三数之和&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;LeetCode&…

接口返回动态列名及动态列数据结构

接口返回动态列名及动态列数据结构代码方案 在开发过程中&#xff0c;有时我们需要处理动态表头和动态列数据的问题。特别是在一些数据统计或报表类需求中&#xff0c;列名和数据都可能随着时间或条件发生变化。本文将结合实际代码和表格展示&#xff0c;详细说明如何在接口中…

微信阅读网站小程序+ssm论文ppt源码调试讲解

第2章 开发环境与技术 微信阅读网站小程序的编码实现需要搭建一定的环境和使用相应的技术&#xff0c;接下来的内容就是对微信阅读网站小程序用到的技术和工具进行介绍。 2.1 MYSQL数据库 本课题所开发的应用程序在数据操作方面是不可预知的&#xff0c;是经常变动的&#xf…

Linux中的tr命令详解

1&#xff0c; 将小写字母转换为大写字母&#xff1a; echo "hello" | tr a-z A-Z但是限定字母的范围的话&#xff0c;是什么输出你们知道吗&#xff1f; echo "hello" | tr a-l A-L2&#xff0c;删除特定字符&#xff1a; 比如&#xff0c;删除所有的数…

【吊打面试官系列-MySQL面试题】MySQL锁的优化策略?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL锁的优化策略?】面试题&#xff0c;希望对大家有帮助&#xff1b; MySQL锁的优化策略? 1、读写分离 2、分段加锁 3、减少锁持有的时间 4.多个线程尽量以相同的顺序去获取资源不能将锁的粒度过于细化&#xff0c;不然可能会…

算法工程师重生之第十六天(二叉搜索树的最小绝对差 二叉搜索树中的众数 二叉树的最近公共祖先 )

参考文献 代码随想录 一、二叉搜索树的最小绝对差 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差值 。 差值是一个正数&#xff0c;其数值等于两值之差的绝对值。 示例 1&#xff1a; 输入&#xff1a;root [4,2,6,1,3] 输出&#x…

语义元分割学习:一种用于少量样本无线图像分类的TinyML方案

论文标题&#xff1a;Semantic Meta-Split Learning: A TinyML Scheme for Few-Shot Wireless Image Classification 中文标题&#xff1a;语义元分割学习&#xff1a;一种用于少量样本无线图像分类的TinyML方案 作者信息&#xff1a; Eslam Eldeeb, Mohammad Shehab, Hirley…

nvm,一款nodejs版本管理工具

背景 在工作中&#xff0c;我们可能同时在进行2个或者多个不同的项目开发&#xff0c;每个项目的需求不同&#xff0c;进而不同项目必须依赖不同版本的NodeJS运行环境&#xff0c;这种情况下&#xff0c;对于维护多个版本的node将会是一件非常麻烦的事情&#xff0c;nvm就是为…

Dapper 如何确保数据的安全性和防止 SQL 注入攻击?

一、什么是SQL注入攻击 SQL注入攻击是一种常见的网络攻击手段&#xff0c;它利用了应用程序中安全措施不足的问题&#xff0c;允许攻击者插入或“注入”一个或多个SQL语句到原本的查询中。这种攻击可以用于获取、篡改或删除数据库中的数据&#xff0c;甚至可以执行一些数据库管…

java:brew安装rabbitmq以及简单示例

什么是消息队列mq 可以看我之前写的这篇 消息队列MQ rabbitmq简介 RabbitMQ是由erlang语言开发&#xff0c;基于AMQP&#xff08;Advanced Message Queue 高级消息队列协议&#xff09;协议实现的消息队列&#xff0c;它是一种应用程序之间的通信方法&#xff0c;消息队列在…

200smart数据日志的功能

称重设备&#xff08;皮带秤&#xff09;读取到的数据值总是一直在跳变&#xff0c;无法正确识别称重传感器读取上来的值来判断产品的重量&#xff0c;虽然在程序中增加了取平均值功能&#xff08;模拟量输入按PLC扫描周期次数求平均值程序&#xff09;&#xff0c;但效果不理想…

什么是聚集索引?

什么是聚集索引&#xff1f; 1、聚集索引的特点2、如何确定聚集索引3、性能优势 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 聚集索引是一种特殊的索引&#xff0c;它直接包含了表中的所有数据行。所以&#xff0c;通过聚集索引&#xf…

代码随想录冲冲冲 Day56 图论Part8

117. 软件构建 这道题是使用拓扑排序的方法 看多个任务有优先级的情况下 怎么排序 对应到这道题就是文件排序 首先要记录每一个点的入度&#xff0c;当一个点的入度为0时&#xff0c;就说明这个点是顶点 然后记录每一个点向那些点相连 之后建立一个queue 寻找一个入度为0的…