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);

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

原文地址:https://www.cnblogs.com/jinkspeng/p/4340188.html