首页>>前端>>JavaScript->JavaScript设计模式综合应用案例

JavaScript设计模式综合应用案例

时间:2023-12-01 本站 点击:0

今天我们模拟小米智能家居应用场景,融合单例模式、组合模式、观察者模式做一个综合应用案例。具体场景如下:

小米门铃为主人开门,触发开门事件;

小米智能控制台监测到开门事件,自动启动小米空调和小米电视;

思路分析

小米控制台,在家庭单位内只有一个实例,我们使用单例模式;

小米控制台通过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 = null        function getXmcSingleton() {            xmcInstance = xmcInstance === null? new XiaomiControl() : xmcInstance            return 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 = null        function getXmcSingleton() {            xmcInstance = xmcInstance === null? new XiaomiControl() : xmcInstance            return 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>

原文:https://juejin.cn/post/7096185381820825613


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