• javascript优化--11模式(设计模式)02


    策略模式

    在选择最佳策略以处理特定任务(上下文)的时候仍然保持相同的接口;

    //表单验证的例子
    var data = {
      firs_name: "Super",
      last_name: "Man",
      age: "unknown",
      username: "o_0"    
    }
    
    validator = {
      types: {},
      message: [],
      config: {},
      validate: function(data) {
        var i, msg, type, checker, result_ok;
        this.message = [];
        for(i in data) {
          if(data.hasOwnProperty(i)) {
            type = this.config[i];
            checker = this.types[type];
            if(!type) continue;
            if(!checker) {
                throw {
                  name: "ValidationError",
                  message: "No handler to validate type " + type       
                };
            }    
            result_ok = checker.validate(data[i]);
            if(!result_ok) {
              msg = "Invalid value for *" + i + "*, " + checker.instructions;
              this.message.push(msg);    
            }
          }    
        }
        return this.hasErrors();  
      },
      //帮助程序
      hasErrors: function() {
        return this.message.length !== 0;  
      }    
    }
    
    validator.config = {
      firs_name: 'isNonEmpty',
      age: 'isNumber',
      username: 'isAlphaNum'    
    }
    
    validator.types = {
      isNonEmpty: {
        validate: function (value) {
          return value !== "";
        },
        instructions: "this value cannot be empty"   
      },
      isNumber: {
        validate: function(value) {
          return !isNaN(value);     
        },
        instructions: "the value can only be a valid number, e.g. 1, 3.14 or 2010"
      },
      isAlphaNum: {
        validate: function(value) {
          return !/[^a-z0-9]/i.test(value);    
        },
        instructions: "the value can only contain characters and number, no special symbols"
      }
    }
    
    validator.validate(data);
    
    if(validator.hasErrors()) {
      console.log(validator.message.join('
    '));    
    }
    
    

    外观模式

    通过把常用方法包装到一个新的方法中,从而提供一个更为便利的API

    //以处理浏览器事件为例
    var myevent = {
      //...
      stop: function(e) {
        (typeof e.preventDefault === 'function') && e.preventDefault();    
        (typeof e.stopPropagation === 'function') && e.stopPropagation();
        //ie
        (typeof e.returnVlaue === 'boolean') && (e.returnVlaue = false);
        (typeof e.cancelBubble === 'boolean') && (e.cancelBubble = true);
      }    
    }
    

    代理模式

    通过包装一个对象以控制对它的访问,其主要方法是将访问聚集为组成或仅当真正必要的时候才执行访问,从而避免了高昂的操作开销

    这种模式的其中一个例子为:延迟初始化;假设初始化对象开销非常大,但客户端可能在初始化对象后从未使用它,这种时候就可以通过代理替换本体对象的接口来解决

    • 首先由客户端发出一个初始化请求,然后代理以一切正常作为响应
    • 但实际上却没有将该消息传递到本体对象;
    • 直到客户端明显需要本体对象完成一些工作的时候,代理财经两个消息一起传递;
    //视频列表例子
    <p><span id="toggle-all">Toggle Checked</span></p>
    <ol id="vids">
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--2158073">Gravedigger</a></li>
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--4472739">Save Me</a></li>
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--45286339">Grush</a></li>
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--2144530">Don't Drink The Water</a></li>
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--217241800">Funny the Way It Is</a></li>
      <li><input type="checkbox" checked><a href="http://new.music.yahoo.com/vides/--2144532">What Would You Say</a></li>
    </ol>
    //未使用代理
    var http = {
      makeRequest: function(ids, callback) {
        var url = 'http://query.yahooapis.com/v1/public/yql?q=',  
            sql = 'select * from music.video.id where ids IN ("%ID%")',
            format = "format=json",
            handler = "callback=" + callback,
            script = document.createElement('script')
        sql = sql.replace("%ID%", ids.join('","'));
        sql = encodeURIComponent(sql);
        url += sql + '&' + format + '&' + handler;
        script.src = url;
        document.body.appendChild(script);
      }   
    }
    var videos = {
      getPlayer: function(id) {},
      updateList: function(data) {},
      //展开折叠信息区域
      getInfo: function(id) {
        var info = $("info" + id);
        if(!info) {
          //负责与服务器通信
          http.makeRequest([id], "videos.updateList");
          return;
        }
        if(info.style.display === "none") {
          info.style.display = '';  
        }	else {
          info.style.display = 'none';
        } 
      }	
    };
    
    var $ = function (id) {
      return document.getElementById(id);	
    };
    $("vids").onclick = function(e) {
      var scr ,id;	
      e = e || window.event;
      src = e.target || e.srcElement;
      //阻止跳转
      if(src.nodeName !== "A") return;
      if(typeof e.preventDefault === "function") e.preventDefault();
      e.returnValue = false;
      id = src.href.split('--')[1];
      //如果是正在播放,即已经展开
      if(src.className == "play") {
      	src.parentNode.innerHTML = videos.getPlayer(id);
      	return;
      }
      src.parentNode.id = "v" + id;
      videos.getInfo(id);
    };
    
    $("toggle-all").onclick = function(e) {
      var hrefs, i, max, id;
      hrefs = $('vids').getElementsByTagName('a');
      for(i = 0, max = hrefs.length; i < max; i += 1) {
        if(hrefs[i].className === "play") continue;
        if(!hrefs[i].parentNode.firstChild.checked) continue;
        id = hrefs[i].href.split('--')[1];
        hrefs[i].parentNode.id = '/' + id;
        videos.getInfo(id);
      }
    }
    //使用代理:就只是将http.makeRequest()改为proxy.makeRequest();
    
    var proxy = {
      ids: [],
      delay: 50,
      timeout: null,
      callback: null,
      context: null,
      makeRequest: function(id, callback, context) {
        //加入列队
        this.ids.push(id);
        this.callback = callback || function(){};
        this.context = context || '';  
        //设置超时时间
        if(!this.timeout) {
          this.timeout = setTimeout(function() {
            proxy.flush();
          }, this.delay);
        }
      },
      flush: function() {
        http.makeRequest(this.ids, 'proxy.handler');
        //清除超时设置和列队
        this.timeout = null;
        this.ids = [];
      },
      handler: function(data) {
        var i, max;
        //单个视频
        if(data.error) return;
        if(parseInt(data.query.count, 10) === 1) {
          proxy.callback.call(proxy.context, data.query.results.Video);
          return;
        }
        //多个视频
        for( i = 0, max = data.query.results.Video.length; i < max; i++) {
          proxy.callback.call(proxy.context, data.query.results.Video[i]);
        }
      }
    }
    

    缓存代理

    代理可以通过将以前的请求结果缓存到新的cache属性中,从而更进一步地保护本体对象http地访问;那么如果videos对象恰好再一次请求同一个视频id,proxy可以直接从缓存中取出该信息

    中介者模式

    通过使对象之间相互并不直接‘通话’,而是仅通过一个中介者对象进行通信,从而促进形成松散耦合

    <p>Player one press "1", player two press "0". Go! (you have half a minute...)</p>
    <div id="results"></div>
    //
    //玩家
    function Player(name) {
      this.points = 0;
      this.name = name;
    }
    Player.prototype.play = function () {
      this.points += 1;
      //中介者的played方法在play调用后,更新score哈希表并传送到记分板
      mediator.played();
    };
    //记分板
    var scoreboard = {  
      element: document.getElementById('results'),  
      update: function (score) {      
        var i, msg = '';
        for (i in score) {
          if (score.hasOwnProperty(i)) {
            msg += '<p><strong>' + i + '</strong>: ';
            msg += score[i];
            msg += '</p>';
          }
        }
        this.element.innerHTML = msg;
      }
    };
    //中介者
    var mediator = {    
      players: {},  
      setup: function () {
        var players = this.players;
        players.home = new Player('Home');
        players.guest = new Player('Guest');    
      },  
      played: function () {
        var players = this.players,
        score = {
          Home:  players.home.points,
          Guest: players.guest.points
        };        
        scoreboard.update(score);
      },  
      keypress: function (e) {
        e = e || window.event; // IE
        if (e.which === 49) { // key "1"
          mediator.players.home.play();
          return;
        }
        if (e.which === 48) { // key "0"
          mediator.players.guest.play();
          return;
        }
      }
    };
    //初始化中介者
    mediator.setup();
    window.onkeypress = mediator.keypress;
    //30s
    setTimeout(function () {
      window.onkeypress = null;
      alert('Game over!');
    }, 30000);
    

    其中记分板与玩家对象并不关联,通过中介者沟通

  • 相关阅读:
    MT4 图表上设置字符
    MC- 交易并设置止损
    MC- 挂单STOP交易
    MC-设置 止盈
    MC 跨周期 画线
    美版MC 使用
    改变和恢复view的方向
    app被Rejected 的各种原因翻译。这个绝对有用。
    更改navigationController push和pop界面切换动画
    线程访问外部数据
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4340188.html
Copyright © 2020-2023  润新知