7种设计模式
1. 工厂模式
优点:封装了对象的创建过程,降低了耦合性,提供了灵活性和可扩展性。
缺点:增加了代码的复杂性,需要创建工厂类。
适用场景:当需要根据不同条件创建不同对象时,或者需要隐藏对象创建的细节时,可以使用工厂模式。
class Button {constructor(text) {this.text = text;}render() {console.log(`Rendering button with text: ${this.text}`);}
}class ButtonFactory {createButton(text) {return new Button(text);}
}const factory = new ButtonFactory();
const button = factory.createButton('Submit');
button.render(); // Output: Rendering button with text: Submit
2.单例模式
优点:确保一个类只有一个实例,节省系统资源,提供全局访问点。
缺点:可能引入全局状态,不利于扩展和测试。
适用场景:当需要全局唯一的对象实例时,例如日志记录器、全局配置对象等,可以使用单例模式。
class Logger {constructor() {if (Logger.instance) {return Logger.instance;}Logger.instance = this;}log(message) {console.log(`Logging: ${message}`);}
}const logger1 = new Logger();
const logger2 = new Logger();console.log(logger1 === logger2); // Output: true
3. 观察者模式
优点:实现了对象之间的松耦合,支持广播通信,当一个对象状态改变时,可以通知依赖它的其他对象进行更新。
缺点:可能导致性能问题和内存泄漏,需要合理管理观察者列表。
适用场景:当需要实现对象之间的一对多关系,一个对象的改变需要通知其他多个对象时,可以使用观察者模式。
class Subject {constructor() {this.observers = [];}addObserver(observer) {this.observers.push(observer);}removeObserver(observer) {const index = this.observers.indexOf(observer);if (index !== -1) {this.observers.splice(index, 1);}}notify(message) {this.observers.forEach((observer) => observer.update(message));}
}class Observer {update(message) {console.log(`Received message: ${message}`);}
}const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('Hello, observers!'); // Output
4.发布订阅模式
优点:解耦了发布者和订阅者,使它们可以独立变化。增加了代码的灵活性和可维护性。
缺点:可能会导致发布者过度发布消息,造成性能问题。订阅者需要订阅和取消订阅相关的逻辑。
适用场景:当存在一对多的关系,一个对象的状态变化需要通知多个其他对象时,可以使用发布订阅模式。
class PubSub {constructor() {this.subscribers = {};}subscribe(event, callback) {if (!this.subscribers[event]) {this.subscribers[event] = [];}this.subscribers[event].push(callback);}unsubscribe(event, callback) {const subscribers = this.subscribers[event];if (subscribers) {this.subscribers[event] = subscribers.filter(cb => cb !== callback);}}publish(event, data) {const subscribers = this.subscribers[event];if (subscribers) {subscribers.forEach(callback => callback(data));}}
}
const pubsub = new PubSub(); // 创建发布订阅对象
const callback1 = data => console.log('Subscriber 1:', data);
const callback2 = data => console.log('Subscriber 2:', data);
pubsub.subscribe('event1', callback1); // 订阅事件
pubsub.subscribe('event1', callback2); // 订阅事件
pubsub.publish('event1', 'Hello, world!'); // 发布事件
pubsub.unsubscribe('event1', callback2); // 取消订阅事件
pubsub.publish('event1', 'Hello again!'); // 再次发布事件
/*** Subscriber 1: Hello, world!Subscriber 2: Hello, world!Subscriber 1: Hello again!*/
-
在上述示例中,PubSub 是发布订阅的实现类,它维护一个订阅者列表 subscribers,用于存储不同事件的订阅者列表。通过 subscribe 方法订阅事件,将回调函数添加到对应事件的订阅者列表中;通过 unsubscribe 方法取消订阅事件,从对应事件的订阅者列表中移除回调函数;通过 publish 方法发布事件,遍历对应事件的订阅者列表,依次执行回调函数。通过发布订阅模式,发布者和订阅者之间解耦,可以实现松散耦合的组件间通信。
-
发布订阅模式适用于许多场景,如事件驱动的系统、消息队列、UI组件间的通信等,可以实现组件之间的解耦和灵活性。
-
发布订阅模式(Publish-Subscribe Pattern)和观察者模式(Observer Pattern)是两种常见的设计模式,它们有一些相似之处,但也存在一些区别。
相似之处:
- 都用于实现对象之间的消息通信和事件处理。
- 都支持解耦,让发布者和订阅者(观察者)之间相互独立。
区别:
- 关注点不同:观察者模式关注的是一个主题对象(被观察者)和多个观察者对象之间的关系。当主题对象的状态发生变化时,它会通知所有观察者对象进行更新。而发布订阅模式关注的是发布者和订阅者之间的关系,发布者将消息发送到一个中心调度器(或者称为事件总线),然后由调度器将消息分发给所有订阅者。
- 中间件存在与否:发布订阅模式通常需要一个中间件(调度器或事件总线)来管理消息的发布和订阅,这样发布者和订阅者之间的通信通过中间件进行。而观察者模式则直接在主题对象和观察者对象之间进行通信,没有中间件的参与。
- 松散耦合程度不同:观察者模式中,主题对象和观察者对象之间是直接关联的,主题对象需要知道每个观察者对象的存在。而在发布订阅模式中,发布者和订阅者之间并不直接关联,它们只与中间件进行通信,发布者和订阅者之间的耦合更加松散。
观察者模式示例:
class Subject {constructor() {this.observers = [];}addObserver(observer) {this.observers.push(observer);}removeObserver(observer) {this.observers = this.observers.filter(obs => obs !== observer);}notify(data) {this.observers.forEach(observer => observer.update(data));}
}class Observer {update(data) {console.log('Received data:', data);}
}// 创建主题对象
const subject = new Subject();// 创建观察者对象
const observer1 = new Observer();
const observer2 = new Observer();// 添加观察者
subject.addObserver(observer1);
subject.addObserver(observer2);// 发送通知
subject.notify('Hello, observers!');
发布订阅模式示例:
class EventBus {constructor() {this.subscribers = {};}subscribe(event, callback) {if (!this.subscribers[event]) {this.subscribers[event] = [];}this.subscribers[event].push(callback);}unsubscribe(event, callback) {const subscribers = this.subscribers[event];if (subscribers) {this.subscribers[event] = subscribers.filter(cb => cb !== callback);}}publish(event, data) {const subscribers = this.subscribers[event];if (subscribers) {subscribers.forEach(callback => callback(data));}}}// 创建事件总线对象const eventBus = new EventBus();// 订阅事件eventBus.subscribe('message', data => {console.log('Received message:', data);});// 发布事件eventBus.publish('message', 'Hello, subscribers!');
在上述示例中,观察者模式中的Subject类相当于发布订阅模式中的EventBus类,Observer类相当于订阅者(观察者),notify方法相当于publish方法,update方法相当于订阅者接收到事件后的回调函数。
观察者模式和发布订阅模式都是常见的用于实现事件处理和消息通信的设计模式,根据实际场景和需求选择合适的模式进行使用。观察者模式更加简单直接,适用于一对多的关系,而发布订阅模式更加灵活,可以支持多对多的关系,并且通过中间件来解耦发布者和订阅者。
5. 原型模式:
- 优点:通过克隆现有对象来创建新对象,避免了频繁的对象创建过程,提高了性能。
- 缺点:需要正确设置原型对象和克隆方法,可能引入深拷贝或浅拷贝的问题。
适用场景:当创建对象的成本较大且对象之间相似度较高时,可以使用原型模式来复用已有对象。
class Shape {constructor() {this.type = '';}clone() {return Object.create(this);}draw() {console.log(`Drawing a ${this.type}`);}
}const circlePrototype = new Shape();
circlePrototype.type = 'Circle';const squarePrototype = new Shape();
squarePrototype.type = 'Square';const circle = circlePrototype.clone();
circle.draw(); // Output: Drawing a Circleconst square = squarePrototype.clone();
square.draw(); // Output: Drawing a Square
6. 装饰者模式(Decorator Pattern)
- 优点:动态地给对象添加新的功能,避免了使用子类继承的方式导致类爆炸的问题。
- 缺点:增加了代码的复杂性,需要理解和管理装饰器的层次结构。
适用场景:当需要在不修改现有对象结构的情况下,动态地添加功能或修改行为时,可以使用装饰者模式。
class Component {operation() {console.log('Component operation');}
}
class Decorator {constructor(component) {this.component = component;}operation() {this.component.operation();}
}class ConcreteComponent extends Component {operation() {console.log('ConcreteComponent operation');}
}class ConcreteDecoratorA extends Decorator {operation() {super.operation();console.log('ConcreteDecoratorA operation');}
}class ConcreteDecoratorB extends Decorator {operation() {super.operation();console.log('ConcreteDecoratorB operation');}
}const component = new ConcreteComponent();
const decoratorA = new ConcreteDecoratorA(component);
const decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB.operation();
// Output:
// Component operation
// ConcreteComponent operation
// ConcreteDecoratorA operation
// ConcreteDecoratorB operation
7. 适配器模式
- 优点:允许不兼容接口的对象协同工作,提高代码的复用性和灵活性。
- 缺点:增加了代码的复杂性,需要理解和管理适配器的转换过程。
适用场景:当需要将一个类的接口转换成客户端所期望的另一个接口时,可以使用适配器模式。
示例代码:
class Target {request() {console.log('Target request');}
}class Adaptee {specificRequest() {console.log('Adaptee specificRequest');}
}class Adapter extends Target {constructor(adaptee) {super();this.adaptee = adaptee;}request() {this.adaptee.specificRequest();}
}const target = new Target();
target.request();
// Output: Target requestconst adaptee = new Adaptee();
const adapter = new Adapter(adaptee);
adapter.request();
// Output: Adaptee specificRequest
在上述示例中,Target 定义了客户端所期望的接口,Adaptee 是一个已有的类,它的接口与 Target 不兼容。适配器 Adapter 继承自 Target,并在其内部持有一个 Adaptee 的引用,通过适配器的 request 方法调用 Adaptee 的 specificRequest 方法,从而实现了对不兼容接口的适配。客户端可以通过调用适配器的 request 方法来使用 Adaptee 的功能。
适配器模式可以用于许多场景,例如在使用第三方库时需要将其接口转换成符合自己代码规范的接口,或者在对旧系统进行重构时需要兼容旧代码和新代码之间的差异。
相关文章:
7种设计模式
1. 工厂模式 优点:封装了对象的创建过程,降低了耦合性,提供了灵活性和可扩展性。 缺点:增加了代码的复杂性,需要创建工厂类。 适用场景:当需要根据不同条件创建不同对象时,或者需要隐藏对象创建…...

el-table合计行合并
效果如下 因为合计el-table的合并方法是不生效的,所以需要修改css下手 watch: {// 应急物资的合计合并planData: {immediate: true,handler() {setTimeout(() > {const tds document.querySelectorAll(".pro_table .el-table__footer-wrapper tr>td");tds[0]…...

新手如何快速上手HTTP爬虫IP?
对于刚接触HTTP爬虫IP的新手来说,可能会感到有些困惑。但是,实际上HTTP爬虫IP并不复杂,只要掌握了基本的操作步骤,就可以轻松使用。本文将为新手们提供一个快速上手HTTP爬虫IP的入门指南,帮助您迅速了解HTTP爬虫IP的基…...

(十五)VBA常用基础知识:正则表达式的使用
vba正则表达式的说明 项目说明Pattern在这里写正则表达式,例:[\d]{2,4}IgnoreCase大小写区分,默认false:区分;true:不区分Globaltrue:全体检索;false:最小匹配Test类似p…...

vue配置@路径
第一步:安装path,如果node_module文件夹中有path就不用安装了 安装命令:npm install path --save 第二步:在vue.config.js文件(如果没有就新建)中配置 const path require("path"); function …...

Ubuntu 18.04 OpenCV3.4.5 + OpenCV3.4.5 Contrib 编译
目录 1 依赖安装 2 下载opencv3.4.5及opencv3.4.5 contrib版本 3 编译opencv3.4.5 opencv3.4.5_contrib及遇到的问题 1 依赖安装 首先安装编译工具CMake,命令安装即可: sudo apt install cmake 安装Eigen: sudo apt-get install libeigen3-…...

【网络基础】IP 子网划分(VLSM)
目录 一、 为什么要划分子网 二、如何划分子网 1、划分两个子网 2、划分多个子网 一、 为什么要划分子网 假设有一个B类IP地址172.16.0.0,B类IP的默认子网掩码是 255.255.0.0,那么该网段内IP的变化范围为 172.16.0.0 ~ 172.16.255.255,即…...

【OCR】合同上批量贴印章
一、需求 OCR算法在处理合同等文件时,会由于印章等遮挡导致文本误识别。因此在OCR预处理时,有一个很重要的步骤是“去除印章”。其中本文主要聚焦在“去除印章”任务中的数据构建步骤:“合同伪印章”的数据构建。下面直接放几张批量合成后效果…...

Stable diffusion 用DeOldify给黑白照片、视频上色
老照片常常因为当时的技术限制而只有黑白版本。然而现代的 AI 技术,如 DeOldify,可以让这些照片重现色彩。 本教程将详细介绍如何使用 DeOldify 来给老照片上色。. 之前介绍过基于虚拟环境的 基于DeOldify的给黑白照片、视频上色,本次介绍对于新手比较友好的在Stable diff…...

在服务器上解压.7z文件
1. 更新apt sudo apt-get update2. 安装p7zip sudo apt-get install p7zip-full3. 解压.7z文件 7za x WN18RR.7z...

【opencv】windows10下opencv4.8.0-cuda C++版本源码编译教程
【opencv】windows10下opencv4.8.0-cuda C版本源码编译教程 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【opencv】windows10下opencv4.8.0-cuda C版本源码编译教程前言准备工具cuda/cudnncmakeopencv4.8.0opencv_contrib CMake编译VS2019编…...

软碟通制作启动盘
一、下载并安装软碟通 二、插入U盘,打开软碟通; 三、在软碟通中选择“文件”-“打开镜像文件”,选择要制作成启动盘的ISO镜像文件; 1.打开要制作的iso文件 选择对应的iso文件 四、在软碟通中选择“启动”-“写入硬盘”ÿ…...

Tomcat和HPPT协议
1.介绍 1.Java EE 规范 JavaEE(java Enterprise Edition):java企业版 JavaEE 规范是很多的java开发技术的总称。这些技术规范都是沿用自J2EE的。一共包括了13个技术规范 2.WEB概述 WEB在计算机领域中代表的是网络 像我们之前所用的WWW&…...
Acwing.4736步行者(模拟)
题目 约翰参加了一场步行比赛。 比赛为期 N 天,参赛者共 M 人(包括约翰)。 参赛者编号为 1∼M,其中约翰的编号为 P。 每个参赛者的每日步数都将被赛事方记录并公布。 每日步数最多的参赛者是当日的日冠军(可以有并…...

前端预览、下载二进制文件流(png、pdf)
前端请求设置 responseType: “blob” 后台接口返回的文件流如下: 拿到后端返回的文件流后: 预览 <iframe :src"previewUrl" frameborder"0" style"width: 500px; height: 500px;"></iframe>1、预览 v…...
搞定ESD(三):ESD干扰耦合路径深入分析(一)
文章目录 一、外部测试环境引发的电场耦合1.1 静电枪枪体的电场耦合1.2 垂直耦合板与水平耦合板的电场耦合二、静电电流泄放路径中的电场耦合2.1 金属平面与敏感信号之间的电场耦合2.2 参考平面与敏感信号布线之间的电场耦合2.3 芯片散热片电场耦合分析2.3.1 散热片静电耦合机理…...

广州华锐互动:炼钢工厂VR仿真实训系统
随着科技的发展,我们的教育体系和职业培训方法也在迅速变化。其中,虚拟现实(VR)技术的出现为我们提供了一种全新的学习和培训方式。特别是在需要高度专业技能和安全性的领域,如钢铁冶炼。本文将探讨如何使用VR进行钢铁…...

适用于音视频的弱网测试整理
一、什么是弱网环境 对于弱网的定义,不同的应用对弱网的定义是有一定的差别的,不仅要考虑各类型网络最低速率,还要结合业务场景和应用类型去划分。按照移动的特性来说,一般应用低于2G速率的都属于弱网,也可以将3G划分…...
【Spring MVC研究】DispatcherServlet如何处理请求(doDispatcher方法)
文章目录 1. 最经典的MVC的使用情况2. 经典情况相关的组件3. 执行3.1. 先看DispatcherServlet的总体过程3.2. 再看RequestMappingHandlerAdapter的总体过程3.2.1. RequestParamMethodArgumentResolver3.2.2. 反射调用 Controller 的方法3.2.3. RequestResponseBodyMethodProces…...

解决github加载过慢问题
github打不开怎么办?看到这篇文章,一切都稳了! DNS被污染,一句话,修改系统hosts文件! 1.hosts文件在哪?C:\Windows\System32\drivers\etc 2.用记事本打开hosts,在最后加入以下两行…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...