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("赚钱养男朋友");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值