【JavaScript】设计模式(单例、策略、发布-订阅)
创始人
2024-05-23 11:18:40
0

💻 【JavaScript】设计模式(单例、策略、发布-订阅) 🏠专栏:JavaScript
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁

文章目录

  • 【JavaScript】设计模式
    • 一. 单例模式
      • (1) 概念
      • (2) 场景
      • (3) 案例:书写一个弹窗
    • 二. 策略模式
      • (1) 概念
      • (2) 场景
      • (3) 案例
      • (4) 优缺点
    • 三. 发布-订阅模式
      • (1) 什么是发布-订阅模式
        • 1. 定义
        • 2. 例子
      • (2) 如何实现发布-订阅模式?
        • 1. 实现思路
        • 2. 具体简单实现例子2:到书店买书
      • (3) 优缺点

【JavaScript】设计模式

一. 单例模式

(1) 概念

单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式核心:实例化一个类的时候

先判断,之前有没有实例化过

  • 如果有,就用之前的
  • 如果没有,就实例化一个新的

单例模式优点:创建对象和管理单例的职责被分布在两个不同的方法中

(2) 场景

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的 window 对象等。

在 JavaScript 开发中,单例模式的用途同样非常广泛。试想一下,当我们单击登录按钮的时候,页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗都只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

(3) 案例:书写一个弹窗

/*分析:
找到一个变量,初始化的时候是null 
第一次实例化后,给这个变量赋值
第二次想要实例化的时候,先去看看这个变量有没有值,如果有,就用之前的
// 一个弹窗的构造函数
class Dialog {constructor(title) {this.title = titlethis.div = document.createElement('div')this.div.style.backgroundColor = 'pink'document.body.appendChild(this.div)}changeTile(title) {this.title = titlethis.div.innerHTML = this.title}
}
// 单例模式代码
// 为了避免instance这个变量污染 改成闭包
const singleton = (function () {// 提前设置一个变量,用来记录该构造函数有没有实例化过let instance = nullreturn function (title) {// 判断构造函数有没有实例化过 // 没有实例化过if (!instance) {instance = new Dialog(title)}// 如果有,就返回这个实例化对象return instance}
})()
// 创建弹窗对象
const res = singleton('hello')
res.changeTile('小花')// 再次创建弹窗对象
const res1 = singleton('你好')
res1.changeTile('你好')
console.log(res1); // Dialog {title: '你好', div: div}

二. 策略模式

(1) 概念

策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

策略模式的目的是:将算法的使用与算法的实现分离开来。

一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体 的算法,并负责具体的计算过程。 第二个部分是环境类Context,Context 接受客户的请求,随后 把请求委托给某一个策略类。要做到这点,说明 Context中要维持对某个策略对象的引用。

(2) 场景

从定义上看,策略模式就是用来封装算法的。但如果把策略模式仅仅用来封装算法,未免有一点大材小用。在实际开发中,我们通常会把算法的含义扩散开来,使策略模式也可以用来封装 一系列的“业务规则”。只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以 用策略模式来封装它们。

(3) 案例

/* 例子  已知一个商品总价 500根据折扣计算实际价格例如:80%  70%  1000-300   800-50
*/
// 通过闭包的形式计算折扣
const calcDiscount = (function () {let priceList = {"80%": function (total) { return (total * 0.8).toFixed(2) },"70%": function (total) { return (total * 0.7).toFixed(2) },"50%": function (total) { return (total * 0.5).toFixed(2) }}function inner(total, type) {if (!priceList[type]) {return "折扣错误";}// 反之折扣正确,返回计算后的价格return priceList[type](total);}// 接下来根据需求定义一系列的算法// 添加折扣inner.add = function (type, fn) {priceList[type] = fn;}// 删除折扣inner.remove = function (type) {delete priceList[type];}// 修改折扣inner.change = function (type, fn) {priceList[type] = fn;}// 查看折扣inner.look = function () {return priceList;}return inner;
})()// 测试算法
// 1.计算价格
// const res = calcDiscount(1400, "80%");
// console.log(res); // 1120.00// 2.添加折扣
// calcDiscount.add("40%", function (total) { return (total * 0.4).toFixed(2) });
// const res = calcDiscount(1500, "40%")
// console.log(res); // 600// 3.删除折扣
// calcDiscount.remove("80%");
// const res = calcDiscount(1200, "80%");
// console.log(res); // 折扣错误  // 4.修改折扣
calcDiscount.change("70%", function (total) { return (total * 0.4).toFixed(2) });
const res = calcDiscount(1200, "70%");
console.log(res); // 480.00// 5.查看折扣
// console.log(calcDiscount.look()); // {80%: ƒ, 70%: ƒ, 50%: ƒ}

(4) 优缺点

优点

  • 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
  • 策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的策略中,使得它们易于切换,易于理解,易于扩展。
  • 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
  • 在策略模式中利用组合和委托来让环境类拥有执行算法的能力,这也是继承的一种更轻便的替代方案。

缺点

  • 增加许多策略类或者策略对象,但实际上这比把它们负责的 逻辑堆砌在环境类中要好。
  • 要使用策略模式,必须了解所有的策略,必须了解各个策略之间的不同点, 这样才能选择一个合适的策略。

三. 发布-订阅模式

(1) 什么是发布-订阅模式

1. 定义

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

2. 例子

例子1:比如我们很喜欢看某个公众号号的文章,但是我们不知道什么时候发布新文章,要不定时的去翻阅;这时候,我们可以关注该公众号,当有文章推送时,会有消息及时通知我们文章更新了。

上面一个看似简单的操作,其实是一个典型的发布订阅模式,公众号属于发布者,用户属于订阅者;用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。

例子2:一个卖书的例子,当你去买书的时候,如果当时有你要买的书,可以直接买到当时当书店没有这本书的时候,你就需要先在书店预订,让老板等书到了通知你,而如果你等待的时候突然又不想买了你可以告诉老板你不要了。

在上述案例中,老板就是发布者,买者就是订阅者,不想要了就是取消订阅。

(2) 如何实现发布-订阅模式?

1. 实现思路

  • 创建一个对象
  • 在该对象上创建一个缓存列表(调度中心)
  • add方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
  • emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
  • remove 方法可以根据 event 值取消订阅(取消订阅)

2. 具体简单实现例子2:到书店买书

class Subscribe {constructor() {// 登记本:存放书籍和操作方法this.message = {};}// 添加订阅消息add(type, fn) {// type:订阅的书籍// fn:书籍到货后的方法// 添加前,判断登记本上是否已经存在这本书籍if (!this.message[type]) {// 如果不存在,设置一个空数组this.message[type] = [];}// 如果存在,不重复登记if (this.message[type].indexOf(fn) !== -1) { return }// 正常登记,添加对应的书籍数据this.message[type].push(fn);console.log(this.message);}// 所需的书籍到货,发布通知emit(type) {// 如果还没有这本书籍if (!this.message[type]) { return }// 如果书籍到货,通知所有想要这本书籍的人this.message[type].forEach(item => item());}// 取消订阅remove(type, fn) {// 如果没有对应的订阅消息if (!this.message[type]) { return }// 取消该书籍所有的订阅消息if (!fn) {delete this.message[type];return;}// 取消对应的订阅消息this.message[type] = this.message[type].filter(item => item !== fn);}
}
// 设置一个卖书的老板
const zs = new Subscribe();
// 进行操作
function fn1() {console.log("小王需要一本");
}
function fn2() {console.log("小张需要一本");
}
// 订阅
zs.add("西游记", fn1); // {西游记: Array(1)}
zs.add("西游记", fn2); // {西游记: Array(2)}
zs.add("三国演义", fn2); // {西游记: Array(2), 三国演义: Array(1)}
// 发布
zs.emit("西游记"); // 小王需要一本 小张需要一本
zs.emit("红楼梦");
// 取消订阅
zs.remove("西游记", fn1); // {西游记: Array(1), 三国演义: Array(1)}
zs.remove("红楼梦");

(3) 优缺点

  1. 优点
    • 对象之间解耦
    • 异步编程中,可以更松耦合的代码编写
  2. 缺点
    • 创建订阅者本身要消耗一定的时间和内存
    • 虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护

结束语

希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪

相关内容

热门资讯

人生路上坎坷多作文 人生路上坎坷多作文(精选28篇)  无论在学习、工作或是生活中,大家都接触过作文吧,借助作文可以宣泄...
梦的翅膀作文 梦的翅膀作文梦的翅膀成功就是让人梦想成真的终点,在通往成功的路上,我们品尝着生活的酸甜苦辣。每当我听...
描写动物的作文 描写动物的作文范文4篇  小兔子太可爱了!小朋友,你们有没有养过这样的小兔子?没有就赶快去养一只吧!...
中秋节赏月的作文400字 中秋节赏月的作文400字汇总7篇  在平平淡淡的学习、工作、生活中,大家都有写作文的经历,对作文很是...
猴年短信祝福语 猴年短信祝福语精选  1、新年佳节到,向你问个好,身体倍健康,心情特别好;好运天天交,口味顿顿妙。最...
各民族的风俗习惯 各民族的风俗习惯各民族的风俗习惯1.藏族藏族主要分布在西-藏,其余在青海、甘肃、四川、云南等地。藏族...
快乐的春节作文300字 【必备】快乐的春节作文300字6篇  在日常学习、工作和生活中,大家都跟作文打过交道吧,通过作文可以...
元宵节花灯字谜 2017年元宵节花灯字谜大全  以下是小编给大家整理的元宵节花灯字谜的内容,欢迎大家查看。  百无一...
行善作文 行善作文600字(通用14篇)  在平平淡淡的日常中,大家都不可避免地要接触到作文吧,借助作文可以宣...
教师节英文祝福语 教师节英文祝福语大全  在日常的学习、工作、生活中,大家都有写祝福语的经历,对祝福语很是熟悉吧,祝福...
过春节的作文900字 关于过春节的作文900字4篇  无论在学习、工作或是生活中,大家对作文都再熟悉不过了吧,通过作文可以...
家乡的春节作文 家乡的春节作文(通用40篇)  在我们平凡的日常里,大家都经常看到作文的身影吧,写作文是培养人们的观...
有意义的暑假生活作文400字 有意义的暑假生活作文400字 虽然美好的暑假生活过去了,那些零零星星的生活碎片我还记忆犹新,特别是那...
春节发生的事的作文 春节发生的事的作文  无论是身处学校还是步入社会,大家都有写作文的经历,对作文很是熟悉吧,作文可分为...
我的爸爸的作文 关于我的爸爸的作文(精选14篇)  在学习、工作乃至生活中,许多人都写过作文吧,借助作文可以宣泄心中...
我的生活作文 【精品】我的生活作文五篇  在我们平凡的日常里,大家对作文都不陌生吧,借助作文可以宣泄心中的情感,调...
我将这样度过寒假作文400字 我将这样度过寒假作文400字  寒假就要来临了!紧张的学习生活,使我的心情一直难以放松。寒假生活可是...
我们的校园作文450字 我们的校园作文450字  我们的校园每个季节都很美。春天鲜花盛开,夏天绿树成阴,秋天红叶似火,冬天白...
种钱想象作文 种钱想象作文  在现实生活或工作学习中,许多人都写过作文吧,借助作文可以宣泄心中的情感,调节自己的心...
路灯作文200字 路灯作文200字(通用58篇)  在学习、工作或生活中,大家都跟作文打过交道吧,借助作文可以宣泄心中...