JS常见设计模式概述

一、前言

今天,与大家分享一下我对在项目中常见的设计模式的理解和认识。

什么是设计模式设计模式就是针对项目中 特定的问题, 做出的简洁而且优化的处理方案

二、设计模式

单例模式

  • 概念:同一个构造函数,生成唯一的实例,防止重复的实例化
  • 优点:节省内存空间,提高程序执行效率
  • 原理:判断构造函数是否生成过实例化对象,没有则new构造函数生成实例化对象,有则返回之前所new出的实例
  • 核心代码:
//核心代码步骤

        //1、创建一个构造函数,用来生成实例
        function CreateObj(){}

        //2、定义一个变量,可以不赋值,或赋值为空
        let res = null;

        //3、建立单例模式的函数
        function Singleton(){
            //如果res中存储的数值为原始数值,也就是我们定义的 null
            //则说明没有new构造函数生成实例
            //可以第一次执行构造函数
            //将构造函数所实例化对象,存储在 res 中

            //之后再次执行程序,res 中已经存储的是一个实例化对象
            //res == null 则为false 便不再生成实例化对象
            if(res == null){
                //此时为第一次生成实例对象,存储在 res 中
                res = new CreateObj();
            }
            //最终的返回值,就是我们创建的变量
            //此变量则存储着 唯一 的实例化对象
            //之后再次执行单例模式,便不再 重复 new 构造函数了
            return res;
        }   
        
        //4、通过单例模式,来生成实例化对象
        const obj1 = Singleton();
        const obj2 = Singleton();

        //不通过单例模式的 (obj1 == obj2) 返回 false
        //此时的 (obj1 == obj2) 则返回 true
        console.log(obj1 == obj2);//true
注意:在实际项目中,要用闭包的形式写,为了防止全局变量污染

组合模式

  • 概念:通过一个‘遥控器’,控制所有‘启动’方法的执行

  • 原理:将所需要执行‘启动’方法的实例对象,写入到一个数组中,通过循环遍历,来执行所有的启动方法

  • 优点:
    1、不必编写大量遍历数组或者其他数据结构的代码
    2、形成一个层次体系,位于顶层的组合对象执行一个操作时,实际上是在对整个结构进行深度优先的搜索以及查找节点,这样查找、添加和删除都特别方便

  • 缺点:由于组合对象调用的任何操作都会被传递到它的所有子对象,如果这个层次体系很大的话,系统性能将会受到影响

  • 核心代码:
    将所有执行方式一样的构造函数中所有的方法都放入这个 init 启动方法中并调用

// 组合模式小demo
        // 目前没有大型项目做演示,看上去,组合模式貌似更麻烦
        // 但组合模式在实际项目中是很有用,也很方便的

		// 定义的几个执行方式一样的构造函数
        class A {
            constructor() { }
            //将此构造函数中所有的方法都放入这个 init 启动方法中
            init() {
                this.a1();
                this.a2();
                this.a3();
            }
            a1() {
                console.log('a1');
            }
            a2() {
                console.log('a2');
            }
            a3() {
                console.log('a3');
            }
        }

        class B {
            constructor() { }
            init() {
                this.b1();
                this.b2();
                this.b3();
                this.b4();
            }
            b1() {
                console.log('b1');
            }
            b2() {
                console.log('b2');
            }
            b3() {
                console.log('b3');
            }
            b4() {
                console.log('b4');
            }
        }

创建组合模式的构造函数

//通过组合模式来启动所有的启动方法
        //组合模式的构造函数
        class Compose {
            constructor() {
                //建立一个空数组,来储存需要启动的构造函数的实例对象
                this.arr = [];
            }

            //将实例对象储存到数组中
            add(obj) {
                this.arr.push(obj);
            }

            //循环遍历这个数组中的实例化对象,调用其中的启动方法
            excute() {
                // 通过forEach循环遍历数组,其中item,存储的就是数组中的实例化对象
                this.arr.forEach(function(item){
                    // 每个实例化对象都有一个启动方法 init()
                    item.init();
                })
            }
        }

        //下面的操作,就是通过组合模式来控制所有的启动方法

        // on_off 就相当于总开关
        const on_off = new Compose();

        //执行 add()方法 就是向总开关中添加需要执行的构造函数的实例对象
        on_off.add(new A());
        on_off.add(new B());
        on_off.add(new C());

        //开启总开关,里边每一个构造函数都会被执行
        on_off.excute();

观察者模式

  • 概念:又叫 发布 - 订阅模式 / 消息模式
  • 应用:一般与框架和双向数据绑定结合使用
  • 核心代码概述:分为5个部分
    1、主体对象
    2、属性 – message盒子,存储执行类型和执行内容(以 对象/数组 形式存储)
    3、add() 添加方法,向消息盒子中,添加需要执行的类型和内容
    4、emit() 发布执行方法,发布消息盒子中类型里的内容
    5、delete() 删除方法,删除消息盒子中与参数对应的类型内容
//观察者模式构造函数
    class Observer {
        constructor() {
            //定义属性,来存储需要执行的函数
            //这个属性也称为消息盒子
            //一般是 对象/数组 形式
            this.message = {};
        }

        //函数1:add()方法,向消息盒子中添加函数
        //参数1:需要执行的事件类型
        //参数2:需要执行的事件内容
        add(type, fn) {
            //判断这个类型是否已经存在
            if (this.message[type]) {
                //如果存在,则将此内容添加到这个类型里
                this.message[type].push(fn);
            } else {
                //如果不存在,则创建此类型,并且将内容以数组的型式存储进去
                this.message[type] = [fn];
            }
        }

        //函数2:emit()方法,执行消息盒子中符合条件的函数
        //参数1:需要执行的类型
        //参数2:需要执行的内容
        //      使用 ...形参 合并运算符 语法形式
        //      将之后的实参,以数组的形式存储在形参中 
        emit(type, ...arr) {
            //判断消息盒子中是否存在此类型,不存在则直接 return 
            if (!this.message[type]) {
                return;
            }

            //这里可以通过双层 for 循环,循环遍历两个数组,数据相同则执行
            //第一个数组 是消息盒子中 对应类型的数组 this.message[type]
            //第二个数组 是形参传入的数组 ...arr
            for (let i = 0; i < this.message[type].length; i++) {
                for (let j = 0; j < arr.length; j++) {
                    //如果两个数组中的数据相同,则执行
                    if (arr[j] == this.message[type][i]) {
                        arr[j]();
                    }
                }
            }
        }

        //函数3:delete()方法,删除消息盒子中存储的函数
        //参数1:需要删除的类型
        //参数2:需要删除类型中的内容
        delete(type, fn) {
            //判断消息盒子中是否存在此类型,不存在则直接 return 
            if (!this.message[type]) {
                return;
            }

            //如果有这个类型,则删除类型中对应的内容
            //循环遍历数组,与需要删除的内容相同,则删除数组中的这个单元
            //注意要防止数组坍塌,需要 i--
            for (let i = 0; i < this.message[type].length; i++) {
                if (fn == this.message[type][i]) {
                    //从当前索引开始,删除一个单元
                    this.message[type].splice(i, 1);
                    //防止数组坍塌,执行 i-- 操作
                    i--;
                }
            }
        }
    }

    //生成实例化对象
    const obj = new Observer();

    //向观察者模式中添加,类型和操作内容(函数名)
    obj.add("girlfriend", girl1);
    obj.add("girlfriend", girl2);
    obj.add("girlfriend", girl3);
    obj.add("application", sleep);
    obj.add("application", wash);
    obj.add("application", money);

    //执行发布操作
    //第一个参数存储在 type 中,其他参数存储在 ...arr 中
    obj.emit("girlfriend", girl1, girl2, girl3);
    obj.emit("application", sleep, wash, money);

    //调用删除方法
    //删除类型中的内容
    obj.delete("application", money);

    //定义被发布的函数
    function girl1() {
        console.log("我是1号女友");
    }
    function girl2() {
        console.log("我是2号女友");
    }
    function girl3() {
        console.log("我是3号女友");
    }
    function sleep() {
        console.log("给男朋友暖被窝");
    }
    function wash() {
        console.log("给男朋友洗衣服");
    }
    function money() {
        console.log("赚钱养男朋友");
    }

武汉加油 中国加油

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值