JavaScript设计模式综合应用案例
今天我们模拟小米智能家居应用场景,融合单例模式、组合模式、观察者模式做一个综合应用案例。具体场景如下:
- 小米门铃为主人开门,触发开门事件;
- 小米智能控制台监测到开门事件,自动启动小米空调和小米电视;
思路分析
- 小米控制台,在家庭单位内只有一个实例,我们使用单例模式;
- 小米控制台通过startWork这一统一接口控制全部智能家居,对于有相同接口的不同实例进行统一调度,我们可以应用组合模式;
- 小米控制台监听小米门铃的开门事件,观察者模式;
定义【组合】和【组件】两个父类接口
后续由小米控制台对【组合】做具体实现,小米电视和小米空调对【组件】做具体实现
/* 组合模式 【组合】父类定义 */class Compose {constructor (name){this.name = name// components 组件调度列表this.components = []}// 添加组件到调度列表addComponent(component){this.components.push(component)}// 轮询所有组件 令其开始工作startWork(){this.components.forEach(component=>{component.startWork()})}}/* 组合模式 【组件】父类定义 */class Component {// 接收组件名称constructor(name){this.name = name}// 所以组件统一调度接口 这里留白等待子类做具体实现startWork(){}}
定义小米控制台类、小米电视类、小米空调类
小米控制台类,通过继承【组合】父类,实现了添加设备和指挥所有设备开始工作
/* 小米控制台 继承【组合】父类 实现添加组件、开始工作两个方法*/class XiaomiControl extends Compose {constructor (){// 调用父类方法为设备命名super("小米总控台")}}
定义小米空调和小米电视类
继承【组件】父类,实现统一调度接口,为后续控制台对它们做统一调度做好准备
class XiaomiKongtiao extends Component {constructor(){super("小米空调")}// 对统一调度接口做具体实现startWork(){console.log(`${this.name}开始调节室温`);}}class XiaomiTV extends Component {constructor(){super("小米电视")}// 对统一调度接口做具体实现startWork(){console.log(`${this.name}自动切换到您喜欢的节目`);}}
设置小米控制台为全局唯一单例
好理解,一个家庭只需要一个控制台实例,通过getXmcSingleton()方法获取该实例
// instance 实例 singleton 单例let xmcInstance = nullfunction getXmcSingleton() {xmcInstance = xmcInstance === null? new XiaomiControl() : xmcInstancereturn xmcInstance}
实现统一调度
// 获取小米控制台实例// const xmControl = new XiaomiControl()const xmControl = getXmcSingleton()// 创建小米电视和小米空调实例const xmKongtiao = new XiaomiKongtiao()const xmTv = new XiaomiTV()// 添加电视和空调到调度列表xmControl.addComponent(xmKongtiao)xmControl.addComponent(xmTv)// 所有智能家居开始工作xmControl.startWork()
小米控制台控制所有智能设备开始工作的时机,为小米门铃开门的一刹那,所以接下来我们通过应用观察者模式实现这一需求;
定义被观察者(数据)和观察者两个父类
被观察者要实现注册观察者、注销观察者、改变数据状态、触发事件(所以观察者响应)四个接口
/* 提供被观察数据的父类接口 */class Observable {constructor(){// 预备存储事件类型和对应的观察者列表this.typeListeners = {}// 预备存储事件类型和对应的值this.typeValue = {}}// 注册观察者addListener(type,...listeners){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){this.typeListeners[type].push(...listeners)}else{this.typeListeners[type] = [...listeners]}}// 注销观察者removeListener(type,listener){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){for(let i=this.typeListeners[type].length-1;i>=0;i--){const item = this.typeListeners[type][i]if(item === listener){this.typeListeners[type].splice(i,1)}}}}// 引起数据变化setValue(type,newValue){this.typeValue[type] = newValue// 数据变化触发事件this.trigger(type,newValue)}// 触发观察者响应trigger(type,newValue){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){this.typeListeners[type].forEach(item=>{item.onEventHappen(type,newValue)})}}}
观察者接口主要需要提供事件响应接口的定义
/* 观察者父类 */class Observer {// 事件响应统一接口,留白待子类做具体实现onEventHappen(type,newValue){}}
小米门铃实现【被观察者/数据】父类,通过继承获得注册设备、注销设备、改变数据和触发事件等具体功能;
在开关门时,会引起doorOpen事件的数据变化,从而触发观察者的响应动作
/* 小米门铃 实现被观察数据接口 开门关门就是事件 */class XiaomiDoorbell extends Observable {// 开门时数据变化 父类帮你会【触发事件】(被观察者所提供的接口)open(){this.setValue("doorOpen",true)}close(){this.setValue("doorOpen",false)}}
小米控制台对观察者父类做具体实现,这里由于前面小米控制台已经继承过一遍【组合】这个父类,而在JavaScript中并不存在标准的多继承,所以这里我们只需要令其实现观察者的onEventHappen(type,value)接口,就能事实上令其成为一个具有观察者功能的类;
扩展后的小米控制台类代码如下:
/* 小米控制台 继承【组合】父类 实现添加组件、开始工作两个方法*/class XiaomiControl extends Compose {constructor (){// 调用父类方法为设备命名super("小米总控台")}// 对【观察者】“父类”的事件响应接口做具体实现// 成为一个“事实上”的观察者onEventHappen(type,newValue){switch (type) {case "doorOpen":if(newValue === true){this.startWork()}break;default:break;}}}
OK,一切准备就绪,接下来创建门铃,添加小米控制台为观察者,并触发开门事件
// 创建小米门铃实例const xmdb = new XiaomiDoorbell()// 添加小米控制台到doorOpen事件的观察者列表xmdb.addListener("doorOpen",xmControl)// 通过按钮、定时器等触发小米门铃开门,进而触发小米控制台响应并令所有设备开始工作// 这里简化一下xmdb.open()
完整代码如下:
<script>/* 提供被观察数据的父类接口 */class Observable {constructor(){// 预备存储事件类型和对应的观察者列表this.typeListeners = {}// 预备存储事件类型和对应的值this.typeValue = {}}// 注册观察者addListener(type,...listeners){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){this.typeListeners[type].push(...listeners)}else{this.typeListeners[type] = [...listeners]}}// 注销观察者removeListener(type,listener){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){for(let i=this.typeListeners[type].length-1;i>=0;i--){const item = this.typeListeners[type][i]if(item === listener){this.typeListeners[type].splice(i,1)}}}}// 引起数据变化setValue(type,newValue){this.typeValue[type] = newValue// 数据变化触发事件this.trigger(type,newValue)}// 触发观察者响应trigger(type,newValue){if(Object.prototype.hasOwnProperty.call(this.typeListeners,type)){this.typeListeners[type].forEach(item=>{item.onEventHappen(type,newValue)})}}}/* 观察者父类 */class Observer {// 事件响应统一接口,留白待子类做具体实现onEventHappen(type,newValue){}}/* 组合模式 【组合】父类定义 */class Compose {constructor (name){this.name = name// components 组件调度列表this.components = []}// 添加组件到调度列表addComponent(component){this.components.push(component)}// 轮询所有组件 令其开始工作startWork(){this.components.forEach(component=>{component.startWork()})}}/* 组合模式 【组件】父类定义 */class Component {// 接收组件名称constructor(name){this.name = name}// 所以组件统一调度接口 这里留白等待子类做具体实现startWork(){}}// instance 实例 singleton 单例let xmcInstance = nullfunction getXmcSingleton() {xmcInstance = xmcInstance === null? new XiaomiControl() : xmcInstancereturn xmcInstance}/* 小米门铃 实现被观察数据接口 开门关门就是事件 */class XiaomiDoorbell extends Observable {// 开门时数据变化 父类帮你会【触发事件】(被观察者所提供的接口)open(){this.setValue("doorOpen",true)}close(){this.setValue("doorOpen",false)}}/* 小米控制台 继承【组合】父类 实现添加组件、开始工作两个方法*/class XiaomiControl extends Compose {constructor (){// 调用父类方法为设备命名super("小米总控台")}// 对【观察者】“父类”的事件响应接口做具体实现// 成为一个“事实上”的观察者onEventHappen(type,newValue){switch (type) {case "doorOpen":if(newValue === true){this.startWork()}break;default:break;}}}class XiaomiKongtiao extends Component {constructor(){super("小米空调")}// 对统一调度接口做具体实现startWork(){console.log(`${this.name}开始调节室温`);}}class XiaomiTV extends Component {constructor(){super("小米电视")}// 对统一调度接口做具体实现startWork(){console.log(`${this.name}自动切换到您喜欢的节目`);}}</script>
JavaScript设计模式综合应用案例相关推荐
- JavaScript设计模式系列四之外观模式(附案例源码)
文章初衷 设计模式其实旨在解决语言本身存在的缺陷, 目前javaScript一些新的语法特性已经集成了一些设计模式的实现, 大家在写代码的时候,没必要为了用设计模式而去用设计模式, 那么我这边为什么还 ...
- Javascript设计模式-超详细笔记
Javascript设计模式 什么是设计模式 1. 什么是设计模式 设计模式是前人总结出的,解决开发中某类问题的方法: 我们在过去的代码编写中已经接触过很多的设计模式了,只不过当时咱们不知道这就是一种 ...
- JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式
JavaScript 设计模式核⼼原理与应⽤实践 之 结构型设计模式 结构型:装饰器模式--对象装上它,就像开了挂 装饰器模式,又名装饰者模式.它的定义是"在不改变原对象的基础上,通过对其进 ...
- educoder头歌Web实训 web课——综合应用案例:动态焦点图页面的制作
educoder头歌Web实训 太原理工web课--综合应用案例:拼图页面的制作[全网更新最快]_玛卡巴卡的博客-CSDN博客 第1关:动态焦点图页面的样式设计 任务描述 本关任务: 完成动态焦点图 ...
- JavaScript设计模式系列—模式篇总结(上)
转载请注明预见才能遇见的博客:http://my.csdn.net/ 原文地址:https://blog.csdn.net/pcaxb/article/details/102517956 JavaSc ...
- 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)
前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经验的凝练和总结,能更大限度的优化代码以及对已有代码的合理重构.作为一名合格的前端工程师 ...
- educoder头歌Web实训 web课——综合应用案例:限时秒杀效果的制作
educoder头歌Web实训 太原理工web课--综合应用案例:动态焦点图页面的制作[全网更新最快]_玛卡巴卡的博客-CSDN博客 第1关:限时秒杀效果图片渲染 [TOC] 图1如下 链接为htt ...
- javascript 设计模式之观察者模式
什么是观察者模式 观察者模式 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新. -- Graph ...
- JavaScript 设计模式核⼼原理与应⽤实践 之 行为型:策略模式——重构小能手,拆分“胖逻辑”
JavaScript 设计模式核⼼原理与应⽤实践 之 行为型:策略模式--重构小能手,拆分"胖逻辑" 行为型:策略模式--重构小能手,拆分"胖逻辑" 策略模式和 ...
最新文章
- NOI2011 道路修建
- 使用VC++ 显示一首诗歌
- MySQL多表查询核心优化
- Linux进程终止命令kill或killall​笔记
- vue-router 如何在当前路由下重新点击当前路由的router-link实现刷新
- C语言之如何理解指针的指针(九)
- Dagger 2 系列(一) -- 前奏篇:依赖注入的基本介绍
- oracle数字进一函数,oracle常用函数一:数字函数
- 如何备份android,如何备份安卓手机系统
- 可禁用计算机服务,哪些Microsoft服务项目可以禁用以提高 电脑速度
- 《二十世纪西方思想文化潮流》笔记--导论5--理性的后果1
- 京东跨端组件库 NutUI 2.0 来袭
- Android视频加水印和压缩
- TencentOS学习笔记(1)
- 英语学习笔记(二)语法
- 洛谷 P1885 Moo
- 关于\xEF\xBB\xBF的介绍
- 计算机网络知识点总结(计网期末盲押系列)
- 谈谈favicon和他带来的问题
- PCA(主成分分析)的理解与应用(学习笔记)
热门文章
- parseInt鲜为人知的用法
- (4)复函数与拉普拉斯变换
- 怎么把桌面计算机放到快速启动栏,如何设置电脑快速启动?
- Python中calendar,time,datetime模块详情解 -------18
- 计算机屏幕灯,这样挑选电脑屏幕灯,同事看了都说靠谱!
- springboot实现敏感字段加密存储,解密显示
- 在配置Intel realsense (D435i)时遇到的问题
- Using getResponseBodyAsStream instead is recommended
- Linux编程定时执行某函数
- 实现一台电脑可上公司内网也可以访问外网