设计模式

134 阅读7分钟

设计模式

1_单例模式

防止,建立过多的,重复冗余的对象 可以节约内存的存储空间

单例模式就是 让 obj1 和 obj2 指向的是 同一个内存地址

//为了防止全局变量污染,使用了闭包的概念
const utils = (function(){
    // 定义一个构造函数
    function CreateObj(){};
    // 定义变量
    let obj = null;
    // 定义判断,写在函数中,这个函数作为返回值
    return function(){
        if(obj === null){
            obj = new CreateObj();
        }
        return obj;
    }

})() ; 

console.log(utils);

const obj1 = utils();
const obj2 = utils();

console.log(obj1 === obj2);
// 执行 utils() 等于就是在 执行 return 的 function函数
// 如果是第一次执行, obj 中存储的是原始的null,会通过构造函数,生成实例化对象
// 之后执行 obj 中 存储的是 实例化对象 , 不是 null , 不会再次执行构造函数,生成新的实例化对象
// 防止重复的实例化对象的生成
2_组合模式

所谓的组合模式,是定义一个构造函数

通过一个构造构造函数,来一次性,启动所有的实例化对象中的入口函数

等于是,一次性的调用启动,所有的实例化对象中的所有的方法

1,基本思路和步骤

​ 通过一个构造函数,来控制所有的实例化对象,其中的入口函数

2,定义一个构造函数

​ 构造器中,定义一个空数组

​ 方法1,向空数组中,添加要控制实例化对象

​ 方法2,循环遍历数组,执行其中添加的实例化对象的入口函数init()

3,代码确实是更加的复杂了,但是我们提高了程序的执行效率和可维护性

​ 可以通过一个方法,调用所有的入口函数

​ 让操作更加的方便灵活

​ 代码的复杂程度---交换---执行程序时更高的效率

class A{
    constructor(){}

    // 定义一个入口函数,统一命名为 init()
    init(){
        this.funA1();
        this.funA2();
        this.funA3();
        this.funA4();
    }

    funA1(){console.log('我是实例化对象A的方法1')}
    funA2(){console.log('我是实例化对象A的方法2')}
    funA3(){console.log('我是实例化对象A的方法3')}
    funA4(){console.log('我是实例化对象A的方法4')}
}

class B{
    constructor(){}

    // 定义一个入口函数,统一命名为 init()
    init(){
        this.funB1();
        this.funB2();
        this.funB3();
    }

    funB1(){console.log('我是实例化对象B的方法1')}
    funB2(){console.log('我是实例化对象B的方法2')}
    funB3(){console.log('我是实例化对象B的方法3')}
}
// 组合模式

// 定义组合模式的构造函数

class Group{
    constructor(){
        // 定义一个空数组,来存储要控制的实例化对象
        this.arr = [];
    }
    // 向数组中添加实例化对象
    add(obj){
        this.arr.push(obj);
    }

    execute(){
        // 数组中,添加的所有的实例化对象的入口函数init()
        // item,就是添加的实例化对象
        this.arr.forEach(function(item){
            item.init();
        })
    }
}


// 1,要通过构造函数,生成响应的实例化对象
const objA = new A();
const objB = new B();

// 2,将实例化对象,添加到构造函数中

const objGroup = new Group();
objGroup.add(objA);
objGroup.add(objB);

objGroup.execute();
3_观察者模式

观察者模式的核心代码

// 需要一个观察者(一个对象)

// 观察者有一个属性(消息盒子) 记录存储要执行的程序内容

// 观察者方法1: on方法 向消息盒子中,添加需要执行的方法程序

// 观察者方法2: emit方法 发布执行消息盒子中,添加的方法程序

// 观察者方法3: off方法 删除消息盒子中,已经添加的方法程序

class CreateObj{
    constructor(){
        this.msg = [];  // 消息盒子,存储要执行的方法
    }

    on(){}      // 向消息盒子 this.msg 中,添加要执行的方法
    emit(){}    // 发布执行,消息盒子 this.msg 中,已经添加的方法 
    off(){}     // 删除消息盒子 this.msg 中,添加的方法
}

观察则模式on方法

class Observer{
    constructor(){
        // 消息盒子,可以是对象,也可以是数组
        this.msg = {};
    }
    // type,就是事件类型
    // fun,就是具体的函数
    on(type,fun){
        // 如果没有这个类型,执行结果,undefined
        // 证明当前消息盒子中,没有这个类型
        if(this.msg[type] === undefined){
            // 就要新增这个类型,并且赋值要执行的函数
            // 因为一个类型中,会有多个函数,添加执行函数时,要是一个数组的形式
            this.msg[type] = [fun] ; 
        }else{
            // 这个类型已经存在了,就只需要,向类型中,数组,新增执行的函数就可以了
            this.msg[type].push(fun);
        }
    }

    emit(){}

    off(){}
}


const observer = new Observer();

// 第一次新增打电话类型,是新增类型,并且赋值一个数组,存储函数
observer.on('打电话' , da1);
// 打电话,类型已经存在,直接向数组中新增函数就可以了
observer.on('打电话' , da2);
 function da1(){
     console.log('请老爸,下午2点来学校');
 }

function da2(){
    console.log('请老妈,下午3点来学校');
}

观察者模式off方法

// 观察者模式的off方法
//   在已经添加到消息盒子中的类型以及方法中,删除方法
//   如果有这个类型,有这个方法,再执行删除操作,如果没有,不做任何操作

class Observer{
    constructor(){
        this.msg = {};
    }
    on(type,fun){
        if(this.msg[type] === undefined){
            this.msg[type] = [fun] ; 
        }else{
            this.msg[type].push(fun);
        }
    }

    emit(){}

    off(type,fun){
        // 如果类型方法存在,再执行删除方法,如果类型方法不存在,不执行任何操作

        // 如果类型不存在
        if( this.msg[type] === undefined ){
            // 执行return,终止程序执行,不做任何操作
            return;
        }

        // 从类型中,查找函数方法,从数组中删除
        this.msg[type].forEach((item,key)=>{
            // 存储的函数,与输入的要删除的函数相同
            if(item === fun){
                // 从当前单元的索引开始,删除一个单元
                this.msg[type].splice(key , 1);

                // 防止数组坍塌
                // 数组只要做删除操作,就要有i--
                // i--;
                // 如果是for循环,就要写i--
            }
        })
    }
}

观察者模式的emit方法

// emit方法,是执行调用,已经存在与消息盒子中,类型中的函数方法
// 也称为发布方法
// 实现的原理和方法
// 执行调用的方法,有可能是一个或者多个,是 不定项 执行
// 需要使用 ...参数 并合运算符,将输入的实参 以 数组的形式存储在 参数中

class Observer{
    constructor(){
        this.msg = {};
    }

    on(type,fun){
        if(this.msg[type] === undefined){
            this.msg[type] = [fun];
        }else{
            this.msg[type].push(fun);
        }
    }

    off(type,fun){
        if(this.msg[type] === undefined){
            return;
        }

        // for循环要防止数组坍塌  i--
        this.msg[type].forEach((item,key)=>{
            if(item === fun){
                this.msg[type].splice(key,1);
            }
        })
    }

    // 第二个参数是 合并运算符,以数组的形式存储之后的所有的实参
    emit(type , ...funArr){
        console.log(funArr);

        // 判断类型如果不存在,直接终止程序
        if(this.msg[type] === undefined){
            return;
        }

        // 如果类型存在,还要判断,函数是否存在
        // 如果存在,再来执行,函数

        // item 是 已经存储的 方法
        // 要与 在 funArr 中 输入 的数组,比较
        // 如果相同,证明消息盒子中,有这个数组,我们再执行
        this.msg[type].forEach((item)=>{
            funArr.forEach((i)=>{
                // item 是已经存储在 消息盒子中的方法
                // i    是通过参数,输入的需要执行的方法
                // 要执行发布的方法,一定是已经存储在消息盒子中的方法
                // 存储在消息盒子中的方法,也不是都发布,也要是参数中有的,要发布的方法
                // 总之,就是消息盒子数组中存储的方法,必须与参数数组中存储的方法,对应上,才会执行发布
                if(item === i){
                    item();
                }
            })
        })
    }
}
整合写法
class Observer{
    constructor(){
        //1 准备消息盒子
        this.message = {};
    }
    //2 订阅的方法
    on(type,fn){
        //如果以前没有人订阅type这个事件,那么this.message里面没有type属性
        if(!this.message[type]){
            //type:是事件类型
            //fn:是事件处理函数
            this.message[type] = [];
        }
        this.message[type].push(fn);
    }
    //3 取消订阅的方法
    off(type,fn){
        if(!this.message[type]){return};
        this.message[type] = this.message[type].filter(function(item){
            return item!=fn
        })

    }
    //4 发布事件的方法
    emit(type){
        if(!this.message[type]){return;}
        //遍历时间函数数组,里面的函数都执行一遍
        this.message[type].forEach(function(item){
            item()
        })
    }
}

//实例化事件监听对象
var o = new Observer();
o.on('click',handleA)
o.on('click',handleB)
o.on('click',handleC)
o.on('abc',handleD)
o.on('abc',handleE)
o.off('click',handleB)
o.emit('abc')
o.emit('click')
//准备一些事件函数备用
function handleA(){
    console.log('A事件发生了')
}
function handleB(){
    console.log('B事件发生了')
}
function handleC(){
    console.log('C事件发生了')
}
function handleD(){
    console.log('D事件发生了')
}
function handleE(){
    console.log('E事件发生了')
}