• js设计模式总结3


    1、模板方法模式

    模板方法就是将多个模型抽象化归一,从中取出一个最基本的模板,当然这个模板可以作为实体对象也可以作为抽象对象,看你具体需求,其他模块只需要继承这个模块方法,也可以扩展这个方法。

    举例子:1、蛋糕的外形都是相同的,都是采用蛋糕模具做出来的,之所以商店里的蛋糕看上去形态各异,其实都是在这基础上的二次加工,所以我们添加了不同的材料。

    2、例如不同的提示框,基本框架是一个提示框,但是标题提示框多了一个标题,取消提示框多了一个取消按钮等等。

    模板方法的核心在于对方法的重用,它将和新方法封装在基类中,让子类继承基类的方法,实现基类方法的共享,达到方法共用。

    2、观察者模式

    观察者模式:又被称作发布-订阅者模式或消息机制,定义了一种依赖关系,解决了主体对象与观察者之间功能的耦合。

    var Observer=(function(){
            //防止消息队列爆满而被篡改故将消息容器作为静态私有变量保存
            var _messages={};
            return {
                //注册信息接口,是将订阅者注册的消息推入到消息对列中
                regist:function(type,fn){
                    if(typeof _messages[type]==='undefined'){
                        _messages[type]=[fn];
                    }else{
                        //将动作方法推入该消息对应的动作执行序列中
                        _messages[type].push(fn);
                    }
                },
                //发布消息接口
                fire:function(type,args){
                    //如果消息没有被注册,则返回
                    if(!_messages[type])
                    return;
                    var events={
                        type:type,
                        args:args||{}
                    },
                    i=0,
                    len=_messages[type].length;
                    for(;i<len;i++){
                        //依次执行注册的消息对应动作序列
                        _messages[type][i].call(this,events);
                    }
                },
                //移除消息接口
                remove:function(type,fn){
                    if(_messages[type] instanceof Array){
                        var i=_messages[type].length-1;
                        for(;i>=0;i--){
                            //如果存在该动作,则移除该动作
                            _messages[type][i]===fn && _messages[type].splice(i,1);
                        }
                    }
                }
            }
        })();

    既然选择用观察者模式来解决问题,首先应该分析哪些模块应该注册消息,哪些模块应该发布消息,这一点是很重要的。

     3、状态模式

    状态模式:当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。

    举例子:比如我们投票,已经确定有好几种状态,如果我们采用if,else,这样要多次判断,效率低,也不方便管理。这是后我们可以将不同的判断结果封装在转态对象内,,然后该状态对象返回一个可被调用的接口方法,用于调用状态内部某种方法。

            var Result=function(){
                //判断结果保存在内部状态中
                var States={
                    //每种状态作为一种独立的方法保存
                    state0:function(){},
                    state1:function(){},
                    state1:function(){}
                }
                //获取某一种状态并执行其对应的方法
                function show(result){
                    States["state"+result]  && States["state"+result]();
                }
                return {
                    //返回调用转态方法接口
                    show:show
                }
                
            }();        

    还有一个经典的例子就是我们经常玩的游戏,就是超级玛丽。玛丽要跳跃,又要开枪,奔跑等,我们总不能用if else来做判断,无形中增加的成本是无法想象的。

    var MarryState=function(){
                //判断结果保存在内部状态中
                var States={
                    //每种状态作为一种独立的方法保存
                    move:function(){},
                    jump:function(){},
                    shoot:function(){}
                }
            };
                
            var Action={
                changeState:function(){
                    //组合通过传递多个参数进行实现
                    var arg=arguments;
                    //重置内部状态
                    _currentState={};
                    //如果有动作则添加动作
                    if(arg.length){
                        //遍历动作
                        for(var i=0,len=arg.length;i<len;i++){
                            //向内部状态中添加动作
                            _currentState[arg[i]]=true;
                        }
                    }
                    //方便链式调用
                    return this;
                },
                goes:function{
                    //遍历内部保存的动作
                    for(var i in _currentState){
                        //动作存在则执行
                        States[i]&&States[i]();
                    }
                    return this;
                }
                return {
                //返回调用转态方法接口
                change:Action.change,
                goes:Action.goes
                }
            };
        //创建一个实例
        var marry=new MarryState();
        marry
            .change("jump","shoot")
            .goes()
            .goes()
            .change("shoot")
            .goes();

    4、策略模式

    策略模式:将定义的一组算法封装起来,使其相互之间可以替换。封装的算法具有一定的独立性,不会随客户端变化。

    举例子:例如你作为商家,要在不同的节日给你商品以不同的折扣形式出售,你会怎么做?采用状态模式?no,状态模式是针对一个对象的而言的,也就是不同的商品你都要写一遍不同的状态。

    对于一种商品的促销策略只用一种情况,而不需要其他促销策略,采用策略模式更为合理。

    相同点:结构上,与状态模式很像,也是内部封装一个对象,然后通过返回的接口实现对内部对象的调用;

    不同点:策略模式不需要管理状态,状态之间没有依赖关系、策略之间可以相互替换、在策略对象内部保存的是相互独立的一些算法。

                var PriceState=function(){
                //内部算法对象
                var States={
                    return30:function(price){},
                    return50:function(price){},
                    pecent80:function(price){},
                    pecent60:function(price){}
                }
                //策略算法调用接口
                return function(algorithm,price){
                    //如果算法存在,则调用算法
                    return States[algorithm]&&States[algorithm](price)
                }
            };

    类似的,表单验证也可以写成类似的形式:

    var InputState=function(){
                //内部算法对象
                var States={
                    notNull:function(value){},
                    number:function(value){},
                    phone:function(value){},
                }
                //策略算法调用接口
                return {
                    check:function(type,value){
                        value=value.replace(/^s+|s+$/g,"");
                        return States[type]&&States[type](value);
                    },
                    addState:function(type,fn){
                        States[type]=fn;
                    }
                }
            };

    但最后我们增加了一个为策略对象增加策略算法的接口,这样我们如果有新的策略对象,只需要通过addState方法即可实现添加,而不用修改内部的代码。

    5、职责链模式;6、命令模式

    (具体看书)

    7、访问者模式

    访问者模式:针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法。也就是在不改变操作对象的同时,为他添加新的操作方法,来实现对操作对象的访问。

    举例子:其实我们可以给对象添加数组的操作方法:比如pop,push。

  • 相关阅读:
    同源策略和跨域知识点学习
    一次脚本注入广告漏洞分析
    一个利用微信分享的项目开发过程以及后续思考
    react-native —— 在Windows下搭建React Native Android开发环境
    ionic —— 开发环境搭建并编译运行第一个APP
    错误: 找不到或无法加载主类
    jekyll and github.io搭建博客遇到的问题
    java 10 生成头文件
    JNI的使用
    vivado error:incorrect freePtr. Call out of sequence?
  • 原文地址:https://www.cnblogs.com/huansky/p/5686570.html
Copyright © 2020-2023  润新知