关于设计模式

214 阅读6分钟

前言

生活中我们时刻能感受到套路的好处,比如用土味情话追妹子,虽然可能会显得你很老土,但是也不至于冷场,起码还显得你幽默。在写代码的过程中同样可以使用一些套路,使你的代码看起来是高雅的、有艺术气息的。设计模式就是这样一种套路,提高你写代码的效率,重用性、让代码更容易被他人理解、保证代码可靠性等等,不仅显得你气质非凡,还显得你666!!!

设计模式的'道德规范'---原则

设计模式的原则就如同我们生活中的道德规范,你可以不去遵循,那在外人看来你就是***。同样你使用设计模式不去遵循设计模式的原则,你的代码也就是那啥。

  1. 单一原则 一次只能做一件事情,单一原则可以减低程序的复杂性,但会随即增加耦合度。上厕所不能同时吃饭,这是一件很恶心的事(这样的代码也着实很恶心),虽然你想秉着节约时间的原则,但你要权衡利弊啊,不要做这么恶心的事。
  2. 里氏替换原则 子类可以替换父类,父类不能替换子类。你喜欢所有的妹子,可以推断出你喜欢你女朋友(因为女朋友是妹子的子集),你喜欢你的女朋友,不能推断出你喜欢所有的妹子(搓衣板跪穿的事!!!)
  3. 开闭原则 关闭修改,开启扩展。小时候,你父亲要求你什么都得会【开启扩展】,但是你不能要求你父亲什么都会(毕竟你知道你不是对手)【关闭修改】。
  4. 最小知道原则 要降低耦合度,降低风险。藏私房钱,只能天知地知我知,才能最大限度保证私房钱的安全。
  5. 依赖倒置原则 同样降低耦合度,比如vuex。你看中了一个妹子,不好意思直接要联系方式,你差你的好兄弟,去找人要联系方式,他拿到联系方式再给你。
  6. 接口分离原则 与单一原则类似,每个接口做一件事。追班花要一个一个的追,追班花时还打望隔壁的班花,班花走了,还得被隔壁班男生追,这不愁人嘛。
  7. 权衡 (可忽略) 不是所有代码都得用设计模式,不是所有设计模式都得遵循所有原则。杀鸡焉用宰牛刀,权衡其利弊才是智者。

设计模式

  • 单例模式

保证一个类只有一个实例,无论执行多少次new操作都生成一个相同的实例

圣杯写法(yahoo提出用圣杯模式去封装一个继承方法)

const siglePattern = (()=>{
    let _onlyObj = null; // 利用闭包,保存唯一的对象
    return function (){
        if(_onlyObj === null){
           this.name = name;
           _onlyObj = this;
        }
        return _onlyObj;
    }
})()

// 封装上面的方法  func为一个正常的构造函数
const singleHandle = function (func){
    let result = null;
    return function () {
        if(result !== null){
            result = func.apply(this,arguments)
        }
        return result;
    }
}

  • 代理模式

实现一个场景:放学给隔壁班花给她送开水,此时你需要一个代理来保证班花放学一定有开水,不然班花就有可能喝不到你的开水

        const classFlower = {
            name: '阿花',
            isClassOver: false,
            leaveSchool() {
                setInterval(() => {
                    if (Math.random() > 0.5) {
                        this.isClassOver = true
                    }

                }, 200);
            },
            reply() {
                console.log(`你好!我是${this.name},谢谢你的开水`)
            }
        }
        classFlower.leaveSchool() // 仅仅为了开启是否放学了
        const Diaos = {
            name: '阿雕',
            sendWater(obj) {
                console.log(`你好,我是${this.name},多喝点开水`)
                if (obj.isClassOver) {
                    obj.reply();
                } else {
                    console.log('班花可能走了,可能还没有下课')
                }
            }
        }
        // 因为事件循环原因,所以将其放置延时器中。
        // Diaos同学只能凭借运气好坏,给班花打招呼
        // 此时Diaos同学就需要找一个代理人,告诉他什么时候该去,才不让自己扑空
        setTimeout(() => {
            Diaos.sendWater(classFlower)
        }, 300);
        const Dproxy = {
            name: '职业班花代理人',
            listener(origin, target) {
                this.tiemr = setInterval(() => {
                    if (target.isClassOver) {
                        clearInterval(this.tiemr)
                        origin.sendWater(target)
                    }
                }, 300);

            }
        }

        Dproxy.listener(Diaos,classFlower) //找班花闺蜜,班花要走的时候通知自己执行打招呼,这样可以告别等待,百发百中。
  • 策略模式

实现表单验证,当点击提交时开始验证

结构代码

    <label for="username">
        username: <input type="text" id="username">
    </label>
    <span class="msg"></span>
    <br>
    <label for="email">
        email: <input type="text" id="email">
    </label>
    <span class="msg"></span>
    <br>
    <!-- 点击提交按钮开始验证 -->
    <button id="btn">submit</button>

js部分代码

    // 构建一个管理验证表单的对象,可通过add方法添加验证方式,run方法执行,extend扩展验证方法
    class Validator {
        constructor () {
            // 缓存验证方式
            this.cache = [];
            // 缓存显示信息的位置,满足条件后清除
            this.showDom = [];

        }
        // 为需要验证的表单值添加验证方式,传值为需要验证的dom,需要把错误显示到的地方,需要用到那些方法(数组)
        add(dom,showDom,methods){
            // 缓存显示位置
            this.showDom.push(showDom)
            // 遍历所需方式
            methods.forEach((ele,index)=>{
                // 这些方法以及参数保存在实例中,开闭原则
                this.cache.push(()=>{
                    // 处理参数
                    const parameter = ele.method.split(':')
                    const method = parameter.shift();
                    parameter.unshift(dom.value);
                    parameter.push(ele.msg);
                    // 执行验证方法并保存结果
                    const result = this.methodStore[method](...parameter);
                    // 判断是否有错误消息,并显示在对应的位置
                    if(result != true){
                        showDom.innerText = result;
                    }
                    return result
                })

            })
        }
        // 执行实例中缓存的方法
        run(){
            // 清除上一次显示的错误信息
            this.showDom.forEach(ele => {
                ele.innerText = ''
            })
           // 最后返回给调用此策略的用户是否通过指定的验证方式
            let flag = true;
            // 执行缓存中的方法
            this.cache.forEach((ele,index)=>{
                if(ele() != true){
                    flag = false;
                }
            })
            // 防止多次验证无限缓存相同方法
            // 可以使用代理模式进行优化
            this.cache.length = 0;
            return flag;
        }
        // 扩展验证方式
        extend(config){
            for (const key in config) {
                this.methodStore[key] = config[key]
            }
        }
    }

    // 验证方式仓库,可通过extend方法进行添加
    Validator.prototype.methodStore = {
        isEmpty(value,msg){
            if(value === ''){
                return msg;
            }
            return true;
        },
        minLength(value,len,msg){
            if(value != '' && value.length < len){
                return msg
            }
            return true;
        }

    }

    // 使用Validator对象,这里可以使用代理模式配合使用
    const validator = new Validator();
    // 使用扩展方式添加验证邮箱
    validator.extend({
        isEmail(value,msg){
            const reg = /^([0-9A-z-_])+@([0-9A-z-_])+(\.[0-9A-z-_]+)/
            if(value != '' && !reg.test(value)){
                return msg;
            }
            return true;
        }
    });
    const oUserName = document.getElementById('username');
    const oMsg = document.getElementsByClassName('msg');
    const oEmail = document.getElementById('email');
    const oBtn = document.getElementById('btn')
    oBtn.onclick = function () {
        validator.add(oUserName,oMsg[0],[{method:'isEmpty',msg:'Empty!!!!'},{method:'minLength:3',msg:'length!!!'}])
        validator.add(oEmail,oMsg[1],[{method:'isEmpty',msg:'Empty!!!!'},{method:'isEmail',msg:'not is email!!!'}])
        validator.run();
    }

总结

设计模式是前辈为我们泡代码提供的一些套路,套路千万条,合适第一条,一定要权衡利弊。滥用设计模式,可能适得其反也就体验不到设计模式的威力。

** 建议看完相应的代码再查阅各个设计模式的定义,以便更好的掌握,区分。