设计模式综合案例:小米家居

336 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

设计模式是什么?

        假设有一个空房间,我们要日复一日地往里面放一些东西。最简单的办法当然是把这些东西 直接扔进去,但是时间久了,就会发现很难从这 个房子里找到自己想要的东西,要调整某几样东 西的位置也不容易。所以在房间里做一些柜子也许是个更好的选择,虽然柜子会增加我们的成 本,但它可以在维护阶段为我们带来好处。使用 这些柜子存放东西的规则,就是一种模式。

学习设计模式,有助于写出可复用和可维护性高的程序。

        其实我们在开发的过程中可能很少会用到设计模式,因为很多东西别人都帮我们封装好了,我们直接拿过来用即可。但是技多不压身,毕竟还要防一手面试呀!

设计模式中常用的都有哪些模式呢?

  • 单例模式
  • 装饰模式
  • 观察者模式
  • 组合模式

其他的就不一一举例了,如果想要深入了解的话,可以到下面的链接里看看噢!

zhuanlan.zhihu.com/p/114011162

JavaScript设计模式_林夏天的博客-CSDN博客_js设计模式 阮一峰

设计模式综合案例:小米家具

本案例主要是在浏览器的控制台输出结果哈,所以效果要通过结合代码和控制台来观察!

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <button id="btn1">外反锁</button>
    <button id="btn2">关灯</button>

    <!-- 
    ·全局共有5件小米智能家居:小米控制台、小米门禁、小米电灯、小米电视;
    ·从外反锁门=>全屋进入【外出模式】=>所有电器自动断电
    ·电灯关闭10分钟=>全屋自动进入【睡眠模式】=>电视关闭+空调进入微风状态+门禁内反锁;
    -->

    <!-- 设计模式底层架构 -->
    <script>
        /* 小米家居基类 */
        class MiDevice {
            constructor(name) {
                this.name = name
            }

            powerOn() {
                console.log(this.name, "powerOn");
            }

            powerOff() {
                console.log(this.name, "powerOff");
            }
        }

        /* 事件源=被观察者(Observable) */
        class DataSource extends MiDevice {
            constructor(name) {
                super(name)
                this.listeners = []
                this.value = null
            }

            // 添加观察者
            addListener(...listeners) {
                this.listeners.push(...listeners)
            }

            // 注销观察者
            removeListener(listener) {
                this.listeners = this.listeners.filter(
                    li => li !== listener
                )
            }

            // 发布事件(通知所有观察者响应)
            publishEvent(event) {
                this.listeners.forEach(
                    li => li.onEvent(event)
                )
            }

        }

        /* 观察者:只要有onEvent(event)方法就是观察者(无论是否显式地继承Observer) */
        class Observer extends MiDevice {
            onEvent(event) {
                console.log(this.name, "onEvent", event);
            }
        }

        /* 组合 */
        class Compose extends MiDevice {
            constructor(name) {
                super(name)
                this.components = []
            }

            // 添加组件
            addComponent(component) {
                this.components.push(component)
            }

            // 注销组件
            removeComponent(component) {
                for (let i = 0; i < this.components.length; i++) {
                    if (this.components[i] === component) {
                        this.components.splice(i, 1)
                        break
                    }
                }
            }

            // 下达号令
            platformSwitchMode(mode) {
                // 让所有组件都响应号令
                this.components.forEach(
                    c => c.switchMode(mode)
                )
            }
        }

        /* 组件: 只要有switchMode(mode)方法就可算是组件(无论是否显式地继承Component) */
        class Component extends MiDevice {
            switchMode(mode) { }
        }

    </script>

    <!-- 家居类封装 -->
    <script>
        /* 小爱同学 */
        class MiControl extends /* Observer */Compose {

            static mode = {
                modeAbsent: "外出模式",
                modeSleep: "睡眠模式"
            }

            static singleton = null
            static getSingleton() {
                !this.singleton && (this.singleton = new MiControl)
                return this.singleton
            }

            constructor() {
                super("小爱同学")
            }

            /* 作为观察者响应事件 */
            /* 我已经有onEvent了 所以我已经是观察者了 无需一定要继承Observer */
            onEvent(event) {
                // super.onEvent(event)
                console.log(this.name, "onEvent", event);

                switch (event.type) {
                    /* 处理门禁事件 */
                    case MiDoor.eventType:
                        if (event.value === MiDoor.mode.lockFromOutside) {
                            // 命令所有组件进入【外出模式】
                            this.platformSwitchMode(MiControl.mode.modeAbsent)
                        }
                        break;

                    /* 处理灯具事件 */
                    case MiLight.eventType:
                        if (event.value === MiLight.mode.sleep) {
                            // 命令所有组件进入【外出模式】
                            this.platformSwitchMode(MiControl.mode.modeSleep)
                        }
                        break;

                    default:
                        break;
                }
            }
        }

        class MiDoor extends DataSource {
            static eventType = "MiDoor"

            static mode = {
                open: "open",
                closed: "closed",
                lockFromInside: "lockFromInside",
                lockFromOutside: "lockFromOutside"
            }

            constructor() {
                super("小米门禁")
            }

            handle(mode) {
                console.log(this.name, mode);

                /* 作为事件源主动发布事件 */
                this.publishEvent({
                    type: MiDoor.eventType,
                    value: mode
                })
            }

            switchMode(mode) {
                console.log(this.name, "switchMode", mode);
                switch (mode) {
                    case MiControl.mode.modeSleep:
                        this.handle(MiDoor.mode.lockFromInside)
                        break;

                    default:
                        break;
                }
            }
        }

        class MiLight extends /* Component */DataSource {
            static eventType = "MiLight"

            static mode = {
                sleep: "睡眠模式",
                ktv: "劲舞模式",
                candleMeal: "烛光晚餐模式",
            }

            constructor() {
                super("MiLight")
            }

            switchMode(mode) {
                switch (mode) {
                    // 外出模式
                    case MiControl.mode.modeAbsent:
                        this.powerOff()
                        break;
                    default:
                        break;
                }
            }

            powerOff() {
                super.powerOff()
                setTimeout(
                    () => {
                        this.publishEvent({
                            type: MiLight.eventType,
                            value: MiLight.mode.sleep
                        })
                    },
                    3000
                )
            }
        }

        class MiTV extends Component {
            constructor() {
                super("MiTV")
            }

            switchMode(mode) {
                switch (mode) {
                    // 外出模式
                    case MiControl.mode.modeAbsent:
                        this.powerOff()
                        break;

                    // 睡眠模式
                    case MiControl.mode.modeSleep:
                        this.sleep()
                        break;
                    default:
                        break;
                }
            }

            sleep() {
                console.log(this.name, "正在静默下载您喜爱的老师的片子...");
            }
        }
    </script>

    <!-- 业务逻辑 -->
    <script>
        const mcontrol = MiControl.getSingleton()

        const mdoor = new MiDoor()
        const mlight = new MiLight()
        const mtv = new MiTV()

        // 小米门禁(事件源)添加小爱同学作为观察者
        mdoor.addListener(mcontrol)
        mlight.addListener(mcontrol)

        /* 所有设备都归小爱同学统一号令 */
        mcontrol.addComponent(mdoor)
        mcontrol.addComponent(mlight)
        mcontrol.addComponent(mtv)

        /* 反锁门 */
        btn1.onclick = function (e) {
            mdoor.handle(MiDoor.mode.lockFromOutside)
        }


        /* 关灯 */
        btn2.onclick = function (e) {
            mlight.powerOff()
        }
    </script>

</body>

</html>