【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. 缺点
    • 创建订阅者本身要消耗一定的时间和内存
    • 虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护

结束语

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

相关内容

热门资讯

照金香山导游词 照金香山导游词  导语:香山公园位于北京西郊,地势险峻,苍翠连绵,占地188公顷,是一座具有山林特色...
云冈石窟导游词 云冈石窟导游词各位游客大家好,很荣幸能当你们的导游,我姓詹,大家可以叫我詹导游。今天,我们将参观举世...
普陀山风景名胜区导游词 普陀山风景名胜区导游词  出历史名城锦州西北行十余里,有一座群峰险壑逶迤伴绕,飞泉云岫横生妙境的名山...
江西省九江庐山牯岭导游词 江西省九江庐山牯岭导游词  作为一名导游,就有可能用到导游词,导游词不是以一代百、千篇一律的,它必须...
台湾阿里山介绍导游词 台湾阿里山介绍导游词  阿里山,台湾地区地名,是台湾地区的著名旅游风景区,阿里山位于台湾省嘉义市东方...
河南内乡县衙导游词 河南内乡县衙导游词  各位游客,大家好!  内乡县衙开始建于元朝大德八年(公元132019年),距今...
导游词的方法技巧以及 导游词的方法技巧以及范文  作为一名尽职尽责的导游,编写导游词是必不可少的,导游词作为一种解说的文体...
导游词结束语怎么写 导游词结束语怎么写  结束语1  各位朋友几天的行程,还有10分钟就要结束了,在此刻要和大家说再见的...
上海南浦大桥导游词 上海南浦大桥导游词  竣工通车于1991年12月1日的南浦大桥,总长8346米,通航净高46米,5....
贵阳河滨公园导游词 贵阳河滨公园导游词  作为一位无私奉献的导游,总归要编写导游词,一篇完整的导游词,其结构一般包括习惯...
天生三桥导游词 关于天生三桥导游词范文(通用9篇)  作为一位出色的导游人员,有必要进行细致的导游词准备工作,借助导...
西安兵马俑英文导游词 西安兵马俑英文导游词(通用10篇)  作为一名优秀的导游,通常需要准备好一份导游词,一篇完整的导游词...
丽江古城中英文导游词 丽江古城中英文导游词  丽江古城被列入世界文化遗产后,丽江的旅游业达到顶峰,成为世人向往的世外桃源、...
观音山导游词 观音山导游词范文  作为一位杰出的导游,很有必要精心设计一份导游词,导游词具有形象、生动、具有感染力...
庐山导游词 庐山导游词(精选4篇)  作为一名专门引导游客、助人为乐的导游,就不得不需要编写导游词,借助导游词可...
大同云冈石窟导游词 大同云冈石窟导游词  云冈石窟佛教艺术按石窟形制、造像内容和样式的发展,小编收集了大同云冈石窟导游词...
明孝陵导游词 明孝陵导游词10篇  作为一名默默奉献的导游,可能需要进行导游词编写工作,导游词具有注重口语化、精简...
无锡九龙灌浴导游词 无锡九龙灌浴导游词  作为一名专门为游客提供优质服务的导游人员,可能需要进行导游词编写工作,导游词由...
灯塔风景区优秀导游词 灯塔风景区优秀导游词  你知道日照吗?日照,取自太阳照耀,就是这样一个太阳照耀下的城市,这里的灯塔风...