javascript 常见设计模式

什么是设计模式?

在软件开发中,设计模式是解决特定问题的经验总结和可复用的解决方案。设计模式可以提高代码的复用性、可维护性和可读性,是提高开发效率的重要手段。

单例模式

1.概念

单例模式 (Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。

2.代码实现

class Singleton {static instance;constructor() {if (!Singleton.instance) {Singleton.instance = this;}return Singleton.instance;}
}const instance1 = new Singleton();
const instance2 = new Singleton();console.log(instance1 === instance2); // true
3.应用场景
  • 浏览器中的 window 和 document 全局变量,这两个对象都是单例,任何时候访问他们都是一样的对象,window 表示包含 DOM 文档的窗口,document 是窗口中载入的 DOM 文档,分别提供了各自相关的方法。
  • element-ui 中以服务方式调用的Loading 是单例的。
  • 项目中的全局状态管理模式 Vuex 维护的全局状态,vue-router`维护的路由实,在单页应用的单页面中都属于单例的应用。
4.优缺点

优点

  • 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。
  • 避免资源的多重占用(如写文件操作)。

缺点

  • 扩展不友好:没有接口,不能继承。
  • 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心实例化方式。

二、发布订阅模式

1.概念

JavaScript 发布订阅模式(Publish/Subscribe Pattern)是一种常用的设计模式。在发布订阅模式中,事件的发生者(发布者)不需要直接调用事件的处理者(订阅者),而是通过一个「发布-订阅中心」来管理事件的发生和处理。具体来说,发布者将事件发布到「发布-订阅中心」中,订阅者可以向「发布-订阅中心」注册事件处理函数,当事件发生时,「发布-订阅中心」会将事件通知给所有注册了该事件处理函数的订阅者,订阅者就可以处理该事件。
发布订阅模式的核心思想是解耦事件的发生和事件的处理,使得事件发生者和事件处理者之间不直接依赖,从而提高程序的灵活性和可维护性。

2.代码实现


/*** @description: 发布订阅* @return {*}*/
// events: {
//   [key]: [{fn: Function, isOnce: Boolean},],
//   [key2]: [{fn: Function, isOnce: Boolean}, ],
// }
class EventBus {events = {}constructor() {this.events = {}}// 注册事件on(key, fn, isOnce = false) {if (!key) returnconst currentEvents = this.events[key]if (!currentEvents) {this.events[key] = []}this.events[key].push({ fn, isOnce })}// onceonce(key, fn) {this.on(key, fn, true)}// 触发事件emit(key, ...args) {if (!key) returnconst currentEvents = this.events[key]if (!currentEvents || !currentEvents.length) {return}this.events[key] = currentEvents.filter((item) => {item.fn(...args)return !item.isOnce})}// 取消订阅off(key, fn = undefined) {if (!this.events[key]) returnif (!fn) {this.events[key] = []} else {this.events[key] = this.events[key].filter((_) => _.fn !== fn)}}
}
const e = new EventBus()function fn1(a, b) { console.log('fn1', a, b) }
function fn2(a, b) { console.log('fn2', a, b) }
function fn3(a, b) { console.log('fn3', a, b) }e.on('key1', fn1)
e.on('key1', fn2)
e.once('key1', fn3)
e.emit('key1', 10, 20) // 触发 fn1 fn2 fn3
e.off('key1', fn1)
e.emit('key1', 100, 200) // 触发 fn2
3.应用场景
4.优缺点

优点

  • 发布-订阅模式的有点非常明显,一为时间上的解耦,二为对象之间的解耦。
  • 应用广泛,既可以用在异步编程中,也可以帮助我们更松耦合的代码编写。

缺点

  • 创建订阅者本身要消耗一定的时间和内存,而且当订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。
  • 发布-订阅模式虽然可以弱化对象之间的联系,但如果过度使用的话,对象与对象之间必要的联系也将被深埋在背后,会导致程序难以跟踪维护和理解。

二、观察者模式

1.概念

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

2.代码实现
let observerId = 1;
let observedId = 10;
//观察者类
class Observer {constructor() {this.id = observerId++;}//观测到变化后的处理update(ob) {console.log("观察者" + this.id + `-检测到被观察者${ob.id}变化`);}
}//被观察者列
class Observed {constructor() {this.observers = [];this.id = observedId++;}//添加观察者addObserver(observer) {this.observers.push(observer);}//删除观察者removeObserver(observer) {this.observers = this.observers.filter(o => {return o.id != observer.id;});}//通知所有的观察者notify() {this.observers.forEach(observer => {observer.update(this);});}
}
let mObserved = new Observed();
let mObserver1 = new Observer();
let mObserver2 = new Observer();mObserved.addObserver(mObserver1);
mObserved.addObserver(mObserver2);mObserved.notify();
3.应用场景

微信公众号,如果一个用户订阅了某个公众号,那么便会收到公众号发来的消息,那么,公众号就是『被观察者』,而用户就是『观察者』

观察者模式 VS 发布订阅模式

在这里插入图片描述

对象关系
  • 观察者模式中,被观察者和观察者之间的关系是一对多的关系,即一个被观察者可以有多个观察者,但是每个观察者只关注一个被观察者。被观察者维护一个观察者列表,当被观察者发生变化时,通知所有观察者进行相应的处理。
  • 发布订阅模式中,发布者和订阅者之间的关系是多对多的关系,即一个发布者可以有多个订阅者,每个订阅者可以关注多个发布者。发布者和订阅者之间通过「发布-订阅中心」进行通信,当发布者发生变化时,通知所有订阅者进行相应的处理。
解耦
  • 在观察者模式中,被观察者和观察者之间的通信是直接的,即被观察者会直接调用观察者的方法进行通信。这种直接的通信方式可能会导致被观察者与观察者之间的耦合度较高。
  • 在发布订阅模式中,发布者和订阅者之间的通信是通过「发布-订阅中心」进行的,即发布者不直接与订阅者通信,而是通过「发布-订阅中心」进行通信。这种间接的通信方式可以降低发布者与订阅者之间的耦合度。

三、策略模式

1.概念

策略模式(Strategy Pattern)指的是定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。
⽬的就是将策略的实现和使用分离。

Context :封装上下文,根据需要调用需要的策略,屏蔽外界对策略的直接调用,只对外提供一个接口,根据需要调用对应的策略;
Strategy :策略,含有具体的算法,其方法的外观相同,因此可以互相代替;
StrategyMap :所有策略的合集,供封装上下文调用;

2.应用(表单校验)

表单验证是一个常见的应用场景,而策略模式可以很好地应用于表单验证的实现。通过策略模式,可以将不同的验证规则封装成策略对象,根据具体的情况选择相应的验证策略进行验证。这样可以实现更加灵活和可扩展的表单验证功能。

// 定义表单验证策略对象
const strategies = {isNotEmpty(value, errorMsg) {if (value === '') {return errorMsg;}},isEmail(value, errorMsg) {const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$/;if (!emailReg.test(value)) {return errorMsg;}},minLength(value, length, errorMsg) {if (value.length < length) {return errorMsg;}},
};// 表单验证类
class Validator {constructor() {this.rules = [];}addRule(value, rule, errorMsg) {this.rules.push(() => strategies[rule](value, errorMsg));}validate() {for (let rule of this.rules) {const errorMsg = rule();if (errorMsg) {return errorMsg;}}}
}// 使用策略模式进行表单验证
const validator = new Validator();
validator.addRule('example@qq.com', 'isNotEmpty', '邮箱不能为空');
validator.addRule('example@qq.com', 'isEmail', '邮箱地址无效');
const error = validator.validate();
if (error) {console.log(error);
} else {console.log('表单验证通过');
}
4.优缺点

优点

  • 算法切换自由:可以在运行时根据需要切换算法。
  • 避免多重条件判断:消除了复杂的条件语句。
  • 扩展性好:新增算法只需新增一个策略类,无需修改现有代码。

缺点

  • 策略类数量增多:每增加一个算法,就需要增加一个策略类。
  • 所有策略类都需要暴露:策略类需要对外公开,以便可以被选择和使用。

四代理模式

1.概念

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代码举例
1、图片懒加载
//图片加载
let imageEle = (function(){let node = document.createElement('img');document.body.appendChild(node);return {setSrc:function(src){node.src = src;}}
})();
//代理对象
let proxyImage = (function(){let img = new Image();img.onload = function(){imageEle.setSrc(this.src);};return {setSrc:function(src){img.src = src;imageEle.setSrc('loading.gif');}}
})();
proxyImage.setSrc('example.png');
2.缓存代理

缓存代理可以作为一些开销大的运算结果提供暂时的存储,下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果

//计算乘积
let mult = function(){let result = 1;for(let i = 0,len = arguments.length;i < len;i++){result*= arguments[i];}return result;
}//缓存代理
let proxy = (function(){let cache = {};reutrn function(){let args = Array.prototype.join.call(arguments,',');if(args in cache){return cache[args];}return cache[args] = mult.apply(this,arguments);}
})();
3.优缺点

优点

  • 职责分离:代理模式将访问控制与业务逻辑分离。
  • 扩展性:可以灵活地添加额外的功能或控制。
  • 智能化:可以智能地处理访问请求,如延迟加载、缓存等。
    缺点
  • 性能开销:增加了代理层可能会影响请求的处理速度。
  • 实现复杂性:某些类型的代理模式实现起来可能较为复杂。

注:更多设计模式待后续补充…

参考链接

  • https://juejin.cn/post/6844904032826294286?searchId=202407012147303848AD829D3DBC1E62B7
  • https://juejin.cn/post/7372514352425926668
  • https://juejin.cn/post/6844904138707337229?searchId=20240701174747B0D1A8A77127F94493AD#heading-19
  • https://www.runoob.com/design-pattern/design-pattern-tutorial.html

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

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

相关文章

单片机语音识别控制蓝牙通信

基于单片机语音识别控制&蓝牙控制 1、Arduino单片机语音控制1.1 直连1.2 蓝牙无线连接1.3 部分核心程序1.4 实物演示 2、51单片机语音控制2.1 直连2.2 蓝牙无线连接2.3 部分核心程序2.4 实物演示 3、STM32单片机语音控制3.1 直连3.2 蓝牙无线连接3.3 部分核心程序3.4 实物演…

器件频频更换为哪桩

曾想象&#xff0c;在一家大型研发型企业里有如下案例&#xff1a; 硬件工程师设计电路选择了器件库中的某器件&#xff0c;在批量试产产品时&#xff0c;却发现没有库存&#xff0c;即时申请采购&#xff0c;却发现货期相当长&#xff0c;一时难以采购&#xff0c;甚至根本不…

填志愿选专业,文科男生如何选专业?

又到了高考分数出炉&#xff0c;无数学子收获喜悦的季节&#xff0c;在分数刚出炉时&#xff0c;很多学生表现的异常兴奋&#xff0c;于他们而言&#xff0c;这么多年的努力终于有了收获&#xff0c;自己该考虑选择什么专业了。而毫不夸张的说&#xff0c;很多人在拿到专业目录…

HarmonyOS开发探索:使用Snapshot Insight分析ArkTS内存问题

识别内存问题 当怀疑应用存在内存问题的时候&#xff0c;首先使用DevEco Profiler的Allocation Insight来度量内存在问题场景下的大小变化以及整体趋势&#xff0c;初步定界问题出现的位置&#xff08;Native Heap/ArkTS Heap/dev等&#xff09;。 在初步识别内存问题出现的位置…

CentOS中使用SSH远程登录

CentOS中使用SSH远程登录 准备工作SSH概述SSH服务的安装与启动建立SSH连接SSH配置文件修改SSH默认端口SSH文件传输 准备工作 两台安装CentOS系统的虚拟机 客户机&#xff08;192.168.239.128&#xff09; 服务器&#xff08;192.168.239.129&#xff09; SSH概述 Secure S…

Mustango——音乐领域知识生成模型探索

Mustango&#xff1a;利用领域知识的音乐生成模型 论文地址&#xff1a;https://arxiv.org/pdf/2311.08355.pdf 源码地址&#xff1a;https://github.com/amaai-lab/mustango 论文题为**“**利用音乐领域知识开发文本到音乐模型’Mustango’”。它利用音乐领域的知识从文本指…

K 近邻、K-NN 算法图文详解

1. 为什么学习KNN算法 KNN是监督学习分类算法&#xff0c;主要解决现实生活中分类问题。根据目标的不同将监督学习任务分为了分类学习及回归预测问题。 KNN&#xff08;K-Nearest Neihbor&#xff0c;KNN&#xff09;K近邻是机器学习算法中理论最简单&#xff0c;最好理解的算法…

钉钉开放AI生态战略的真正价值到底是什么?很多人都没看懂

来源&#xff1a; 首席数智官 hello 大家好&#xff0c;我们是数字化领军者都在看的首席数智官。 关注我&#xff0c;每天给你讲一个商业案例。 今天我们要给你讲的是&#xff1a;钉钉开放AI大模型生态的战略意义到底是什么&#xff1f; 「谁先赢得苹果&#xff0c;谁就赢得…

AI大模型日报#0701:Meta发布LLM Compiler、扒一扒Sora两带头人博士论文

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE-4.0-8K-latest&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff01;《AI大模型日报》今日要点&#xf…

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数 0. 引言1. 关于m_pcolor2. 关于m_image3. 关于m_shadedrelief4. 关于m_hatch5. 结语 0. 引言 本篇介绍下m_map中区域填充函数&#xff08;m_hatch&#xff09;、绘制伪彩色图…

2.2章节python的变量和常量

在Python中&#xff0c;变量和常量有一些基本的概念和用法&#xff0c;但需要注意的是&#xff0c;Python本身并没有内置的“常量”类型。然而&#xff0c;程序员通常会遵循一种约定&#xff0c;即使用全部大写的变量名来表示常量。 一、变量 在Python中&#xff0c;变量是一…

毫米波雷达深度学习技术-2.1~2.2深度度量学习和成对方法

2 深度度量学习 有几种雷达应用程序旨在对一组预定义的类别进行分类&#xff0c;例如不同的人类活动或手势。然而&#xff0c;在实际环境中&#xff0c;存在的类不仅仅是预定义的类&#xff0c;这就把问题变成了一个开放集的分类任务。开放集分类意味着网络应该能够检测输入是否…

Chapter 8 Feedback

Chapter 8 Feedback 这一章我们介绍feedback 反馈运放的原理. 负反馈是模拟电路强有力的工具. 8.1 General Considerations 反馈系统如下图所示 Aolamp open-loop gain即开环增益. Aolxo/xi β \beta β 是 feedback factor, 注意方向. β x f x o \beta\frac{x_{f}}{x_{o…

一、课程介绍,基础—环境安装、判断、循环语句等(爬虫及数据可视化)

一、课程介绍&#xff0c;基础—环境安装、判断、循环语句等&#xff08;爬虫及数据可视化&#xff09; 1. 课程介绍1.1 相关内容1.2 学习目标1.3 学习内容安排 2. python2.1 环境配置2.2 标识符和关键字2.3 运算符2.4 判断语句2.5 循环语句 1. 课程介绍 1.1 相关内容 10天的…

【pytorch11】高阶操作

高阶操作 WhereGather where 三个参数&#xff0c;第一个是condition&#xff0c;第二个参数是源头A&#xff0c;第三个参数是源头B&#xff0c;也就是说有两项数据A和B&#xff0c;C有可能来自于A也有可能来自于B&#xff0c;如果全部来自于A的话直接赋值给A&#xff0c;如果…

算法金 | Transformer,一个神奇的算法模型!!

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 抱个拳&#xff0c;送个礼 在现代自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Transformer 模型的出现带来了革命性的变…

无线物联网练习题

文章目录 选择填空简答大题 选择 不属于物联网感知技术的是(A) A:ZigBee B:红外传感器 C:FRID D:传感器 ZigBee是一种无线通信技术&#xff0c;虽然它常用于物联网中作为设备之间的通信手段&#xff0c;但它本身并不是一种感知技术 关于物联网于与互联网的区别的描述&#xff…

【机器学习】基于Transformer的迁移学习:理论与实践

引言 在机器学习领域&#xff0c;迁移学习已成为提升模型训练效率和性能的重要策略&#xff0c;特别是在标注数据稀缺的场景下。Transformer模型自2017年由Google提出以来&#xff0c;在自然语言处理&#xff08;NLP&#xff09;领域取得了突破性进展&#xff0c;并逐渐扩展到…

Zuul介绍

Zuul 是 Netflix 开源的一个云平台网络层代理&#xff0c;它主要用于路由、负载均衡、中间件通信和动态路由。Zuul 本质上是一个基于 JVM 的网关&#xff0c;它提供了以下功能&#xff1a; 1.路由&#xff1a;Zuul 允许客户端和服务器之间的所有入站和出站请求通过一个中心化的…

小红书怎么保存无水印图?

使用小红书APP长按保存的图片代有水印&#xff0c;很多人想知道保存小红书无水印图片的方法。本文教你如何保存到无水印的小红书图片&#xff0c;但是请注意不要侵犯作者图片的版权。 小红书怎么保存无水印图&#xff1f; 1、手机上打开小红书APP&#xff1b; 2、打开后&#…