前端常见的设计模式

        //单例模式(一个类只能构造出唯一实例)
        //应用案例:弹框(按钮创建弹窗,不采用单例模式的话每次点击都会创建一个弹窗而单例模式不管点击多少次都只会创建一个)
        class Single {
            constructor(name) {
                this.name = name;
            }
            //静态方法创建唯一实例
            static getInstance(name) {
                if (!this.Instance) {
                    this.Instance = new Single(name)
                }
                return this.Instance;
            }
            //destroy销毁唯一实例,不要再次受到影响
            static destroy() { this.Instance = false; }
        }
        //let Instance1 = Single.getInstance('Instance1'); //实例化一个对象,并保持单例模式。生成的对象只能
        //console.log(Single.prototype)//Instance: Single {name: 'Instance1'}
        //debugger;
        //Single.destroy()
        //console.log(Single.prototype)//Instance:false
        
        //===============================================================================
        //策略模式(根据不同参数命中不同的策略)
        //应用案例:表单验证
        //策略对象
        const strategies = {
            //trim()去除前后空格
            // 验证是否为空
            isNoEmpty: function (value, errorMsg) {
                if (value.trim() === "") {
                    return errorMsg;
                }
            },
            // 验证最小长度
            minLength: function (value, length, errorMsg) {
                if (value.trim().length < length) {
                    return errorMsg;
                }
            },
            // 验证最大长度
            maxLength: function (value, length, errorMsg) {
                if (value.length > length) {
                    return errorMsg;
                }
            },
            // 验证手机号
            isMobile: function (value, errorMsg) {
                if (
                    !/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[7]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(
                        value
                    )
                ) {
                    return errorMsg;
                }
            }
        }
        // 验证类
        class Validator {
            constructor() {
                this.cache = []; // 存储要验证的方法
                this.errList = []; // 存储最终的验证结果
            }
            add(value, rules) {
                for (let i = 0, rule; (rule = rules[i++]);) {
                    console.log(rule)
                    let strategyAry = rule.strategy.split(":");
                    let errorMsg = rule.errorMsg;
                    this.cache.push(() => {
                        let strategy = strategyAry.shift();
                        strategyAry.unshift(value);
                        strategyAry.push(errorMsg);
                        // 执行策略对象中的不同验证规则
                        let error = strategies[strategy](...strategyAry);
                        if (error) {
                            this.errList.push(error);
                        }
                    });
                }
            }
            start() {
                for (let i = 0, validatorFunc; (validatorFunc = this.cache[i++]);) {
                    validatorFunc();
                }
                return this.errList;
            }
        }

        let validataFunc = function (info) {
            let validator = new Validator();
            validator.add(info.userName, [
                {
                    strategy: "isNoEmpty",
                    errorMsg: "用户名不可为空"
                },
                {
                    strategy: "minLength:2",
                    errorMsg: "用户名长度不能小于2位"
                }
            ]);
            validator.add(info.password, [
                {
                    strategy: "minLength:6",
                    errorMsg: "密码长度不能小于6位"
                }
            ]);
            validator.add(info.phoneNumber, [
                {
                    strategy: "isMobile",
                    errorMsg: "请输入正确的手机号码格式"
                }
            ]);
            return validator.start();
        };

        // 需要验证表单的对象
        let userInfo = {
            userName: "王",
            password: "1234",
            phoneNumber: "666"
        };
        let errorMsg = validataFunc(userInfo);
        console.log(errorMsg); // ['用户名长度不能小于2位', '密码长度不能小于6位', '请输入正确的手机号码格式']

        //===============================================================================
        //装饰者模式(在不改变对象自身的基础上,动态地给某个对象添加一些额外的职责)
        //应用案例:在函数执行前后添加新的方法
        function fuc() {
            console.log(2);
        }
        Function.prototype.before = function (beFn) {
            let self = this;
            return function () {
                beFn.apply(this, arguments); // 先执行插入到前面的方法,类似于二叉树的前序遍历
                return self.apply(this, arguments); // 后执行当前的方法
            };
        };
        Function.prototype.after = function (afFn) {
            let self = this;
            return function () {
                self.apply(this, arguments); // 先执行当前的方法
                return afFn.apply(this, arguments); // 后执行插入到后面的方法
            };
        };

        function fuc1() {
            console.log(1);
        }
        function fuc3() {
            console.log(3);
        }
        function fuc4() {
            console.log(4);
        }

        fuc = fuc.before(fuc1).before(fuc4).after(fuc3);
        //fuc();
        // 最终打印结果:4 1 2 3

        //===============================================================================
        //组合模式(组合模式在对象间形成树形结构组合模式中基本对象和组合对象被一致对待无须关心对象有多少层, 调用时只需在根部进行调用)
        //应用案例:打印文件目录
        class Combine {
            constructor() {
                this.list = [];
            }
            add(data) {
                this.list.push(data); //将数据加入列表中
                return this;
            }
            excute() {
                for (let i = 0; i < this.list.length; i++) {
                    this.list[i].excute()
                }
            }
        }
        let file1 = new Combine();
        file1.add({ excute() { console.log(1) } }).add({ excute() { console.log(2) } })
        let file2 = new Combine();
        file2.add({ excute() { console.log(3) } }).add({ excute() { console.log(4) } })
        let file3 = new Combine();
        file3.add(file1).add(file2)
        file3.excute()//1234
        console.log(file3)//[[[],[]],[[],[]]]

        //===============================================================================
        //工厂模式(工厂模式是用来创建对象的一种最常用的设计模式,不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,这个函数就可以被视为一个工厂)
        //应用案例:jquery中的window.$
        class Sheep {
            constructor(color, age) {
                this.color = color;
                this.age = age;
            }
        }
        function createSheep(color, age) { //Factory Pattern的命名方式, 不同的模式对象可以使用不
            return new Sheep(color, age); //returns an object, not a function. 这意味着不能直接在工厂函数
        }
        let redSheep = createSheep('red', 1);
        console.log(redSheep)//{color: 'red', age: 1}

        //===============================================================================
        //访问者模式(在不改变该对象的前提下访问其结构中元素的新方法)
        //应用案例:babel插件
        class Student {
            constructor(name, chinese, math, english) {
                this.name = name;
                this.chinese = chinese;
                this.math = math;
                this.english = english;
            }

            accept(visitor) {
                visitor.visit(this);
            }
        }

        // 访问者类
        class ChineseTeacher {
            visit(student) {
                console.log(`语文${student.chinese}`);
            }
        }

        class MathTeacher {
            visit(student) {
                console.log(`数学${student.math}`);
            }
        }

        class EnglishTeacher {
            visit(student) {
                console.log(`英语${student.english}`);
            }
        }

        // 实例化元素类
        const student = new Student("张三", 90, 80, 60);
        // 实例化访问者类
        const chineseTeacher = new ChineseTeacher();
        const mathTeacher = new MathTeacher();
        const englishTeacher = new EnglishTeacher();
        // 接受访问
        student.accept(chineseTeacher); // 语文90
        student.accept(mathTeacher); // 数学80
        student.accept(englishTeacher); // 英语60

        //===============================================================================
        //发布订阅模式(订阅者订阅相关主题,发布者通过发布主题事件的方式,通知订阅该主题的对象)
        //应用案例:EventBus
        class EventBus {
            constructor() {
                this.task = {};
            }
            //订阅和注册事件
            on(type, fn) {
                //判断this.task是否拥有这个元素,如果没有代表该事件还没有注册则注册,如果有代表这个元素已经注册过了就订阅
                if (!this.task[type]) {
                    this.task[type] = [];
                }
                this.task[type].push(fn);
            }
            //发布事件到相应的事件主题上,通知订阅者对应的函数。也就是说,发布者可以通过调用它的函数来通知订阅者。这个函数应该接受一个参数,
            //指定要发送到哪个事件主题上。如果没有发送到相应的事件主题上,则不
            //发送。或者,如果有发送到相应的事件主题上,则发送。或者,如果  没有发送到任何事件主题上,则直接忽略该操作。 (发送的是一个消息
            emit(type, ...args) {
                //找到要发送的事件主题的数组,如果没有则直接忽略该操作
                if (this.task[type]) {
                    this.task[type].forEach(fn => {
                        fn.apply(this, args)//this指向EventBus的实例
                    });
                }
            }
            off(type, fn) {
                // 删除事件
                if (this.task[type]) {
                    this.task[type] = this.task[type].filter(item => item !== fn);
                }
            }
        }
        let event = new EventBus();
        event.on("change", (...args) => {
            console.log('args');
        });
        event.emit("change", 1, 2);
        event.emit("change", 2, 3);

        //===============================================================================
        //观察者模式(一个对象有一系列依赖于它的观察者(watcher),当对象发生变化时,会通知观察者进行更新)
        //应用案例:vue 双向绑定
        let data = {
            name: "ming",
            age: 18
        };
        Object.keys(data).forEach(key => {
            let value = data[key];
            Object.defineProperty(data, key, {
                get() {
                    console.log("get", value);
                    return value;
                },
                set(newValue) {
                    console.log("更新");
                    value = newValue;
                }
            });
        });
        data.name = "佩奇";
        console.log(data.name);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值