博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
06享元、责任链
阅读量:5277 次
发布时间:2019-06-14

本文共 7409 字,大约阅读时间需要 24 分钟。

享元模式

  • 是一种用于性能优化的模式;
  • 核心是运用共享技术来有效支持大量细粒度的对象,避免对象间拥有相同的内容造成多余的开销;

内部状态和外部状态

  • 享元模式要求对象的属性划分为内部状态和外部状态;
  • 目标是减少共享对象的数量;
    • 内部状态存储于对象内部;
    • 内部状态可以被一些对象共享;
    • 内部状态独立于具体的场景,通常不会改变;
    • 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享;
  • 这样可以吧所有内部状态相同的对象都指定为同一个共享的对象;而外部状态从对象身上剥离并存储在外部;

文件上传例子

var Upload = function( uploadType, fileName, fileSize ){  this.uploadType = uploadType;  this.fileName = fileName;  this.fileSize = fileSize;  this.dom= null;};Upload.prototype.init = function( id ){  var that = this;  this.id = id;  this.dom = document.createElement( 'div' );  this.dom.innerHTML = '文件名称:'+ this.fileName +', 文件大小: '    + this.fileSize +'' + '';  this.dom.querySelector( '.delFile' ).onclick = function(){    that.delFile();  }  document.body.appendChild( this.dom );};Upload.prototype.delFile = function(){  if(this.fileSize < 3000)    return this.dom.parentNode.removeChild( this.dom );  if(window.confirm('确定要删除该文件吗? ' + this.fileName))    return this.dom.parentNode.removeChild( this.dom );};    var id = 0;window.startUpload = function( uploadType, files ){ //uploadType 区分是控件还是flash  for(var i = 0, file; file = files[i++];){    var uploadObj = new Upload( uploadType, file.fileName, file.fileSize );    uploadObj.init( id++ ); // 给upload 对象设置一个唯一的id  }};startUpload( 'plugin', [{  fileName: '1.txt',  fileSize: 1000} , {  fileName: '2.html',  fileSize: 3000}]);startUpload( 'flash', [{  fileName: '3.txt',  fileSize: 1000}]);
  • 享元模式修改
var Upload = function(uploadType){  this.uploadType = uploadType;};Upload.prototype.delFile = function(id){  uploadManager.setExternalState(id, this);  if(this.fileSize < 3000)    return this.dom.parentNode.removeChild(this.dom);  if(window.confirm('确定要删除该文件吗? ' + this.fileName))    return this.dom.parentNode.removeChild(this.dom);};//工厂实例化var UploadFactory = (function(){  var createdFlyWeightObjs = {};  return {    create: function(uploadType){      if(createdFlyWeightObjs[uploadType])        return createdFlyWeightObjs[uploadType];      return createdFlyWeightObjs[uploadType] = new Upload(uploadType);    }  }})();//管理器:剥离和封装外部状态var uploadManager = (function(){  var uploadDatabase = {};  return {    add: function(id, uploadType, fileName, fileSize){      var flyWeightObj = UploadFactory.create(uploadType);      var dom = document.createElement('div');      dom.innerHTML = '文件名称:'+ fileName +', 文件大小: '        + fileSize +'' + '';      dom.querySelector('.delFile').onclick = function(){        flyWeightObj.delFile( id );      }      document.body.appendChild(dom);      uploadDatabase[ id ] = {        fileName: fileName,        fileSize: fileSize,        dom: dom      };      return flyWeightObj;    },    setExternalState: function( id, flyWeightObj ){      var uploadData = uploadDatabase[id];      for (var i in uploadData)        flyWeightObj[i] = uploadData[i];    }  }})();var id = 0;window.startUpload = function(uploadType, files ){    for(var i = 0, file; file = files[i++]; )      var uploadObj = uploadManager.add(++id, uploadType, file.fileName, file.fileSize);};startUpload( 'plugin', [{  fileName: '1.txt',  fileSize: 1000} , {  fileName: '2.html',  fileSize: 3000}]);startUpload( 'flash', [{  fileName: '3.txt',  fileSize: 1000}]);

翻页的例子

var articles = [];  for(var m = 0; m < 12; m++) {    articles.push('这是第'+ m + '条信息')  };  var Flyweight = function () {    var created = [];    function create() {      var dom = document.createElement('div');      document.getElementById('container').appendChild(dom);      created.push(dom);      return dom;    }    return {      getDiv: function () {        if(created.length < 5) {          return create();        } else {          var div = created.shift();          created.push(div);          return div;        }      }    }  }();  var pager = 0, num = 5, len = articles.length;  for(var i = 0; i < 5; i++) {    Flyweight.getDiv().innerHTML = articles[i];  }  document.getElementById('next_page').onclick = function () {    if(articles.length < 5) return;    var n = ++pager * num % len, j = 0;    for(; j < 5; j++) {      if(articles[n + j]) {        Flyweight.getDiv().innerHTML = articles[n + j];      } else if(articles[n + j - len]) {        Flyweight.getDiv().innerHTML = articles[n + j - len];      } else {        Flyweight.getDiv().innerHTML = '';      }    }  }

适用性

  • 使用享元模式会多维护一个factory对象和一个manager对象;所有一般以下情况比较适用享元模式:
    • 一个程序中使用了大量相似的对象,并造成很大的内存开销;
    • 对象的大多数状态都可以变为外部状态,剥离外部状态后可以用相对少的贡献对象取代;

职责链模式

  • 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系;将这些对象连城一条链,并沿着这条链传递请求,直到有一个对象处理它为止;

实际开发中的一个例子

  • 变量
    • orderType:订单的级别,分别为1,2,3;
    • pay:是否支付过定金,false的话统一降到3;
    • stock:库存量,1,2级别不受此此限制;
  • 初级代码的话会用大量if-else来判断分支;这样耦合度很大且不利于以后修改和维护;使用职责链修改
var order500 = function(orderType, pay, stock) {  if(orderType === 1 && pay === true) {    console.log('1级订单,已支付');  } else {    return 'nextSuccessor';  }};var order200 = function(orderType, pay, stock) {  if(orderType === 2 && pay === true) {    console.log('2级订单,已支付');  } else {    return 'nextSuccessor';  }};var orderNormal = function(orderType, pay, stock) {  if(stock > 0) {    console.log('普通购买');  } else {    console.log('库存不足');  }};var Chain = function (fn) {  this.fn = fn;  this.successor = null;};Chain.prototype.setNextSuccesor = function (successor) {  return this.successor = successor;};Chain.prototype.passRequest = function() {  var ret = this.fn.apply(this, arguments);  if(ret === 'nextSuccessor')    return this.successor && this.successor.passRequest.apply(this.successor, arguments);  return ret;};var ChainOrder500 = new Chain(order500);var ChainOrder200 = new Chain(order200);var chainOrderNormal = new Chain(orderNormal);ChainOrder500.setNextSuccesor(ChainOrder200);ChainOrder200.setNextSuccesor(chainOrderNormal);ChainOrder500.passRequest(1, true, 1000);ChainOrder500.passRequest(2, true, 1000);ChainOrder500.passRequest(3, true, 1000);ChainOrder500.passRequest(1, false, 0);

异步的职责链

Chain.prototype.next = function() {  return this.successor && this.successor.passRequest.apply(this.successor, arguments);};//测试var fn1 = new Chain(function() {  console.log(1);  return 'nextSuccessor';})var fn2 = new Chain(function() {  console.log(2);  var self = this;  setTimeout(function() {    self.next();  }, 1000)});var fn3 = new Chain(function() {  console.log(3);});fn1.setNextSuccesor(fn2).setNextSuccesor(fn3);fn1.passRequest();

用AOP实现职责链

Function.prototype.after = function(fn) {  var self = this;  return function() {    var ret = self.apply(this, arguments);    if(ret = 'nextSuccessor')      return fn.apply(this, arguments);  }};var oredr = order500.after(order200).after(orderNormal);order(1, true, 1000);order(2, true, 1000);order(1, fasle, 1000);
  • 这种把函数叠在一起的方法同时也增加了函数的作用域;如果链条太长的话,也会对性能有较大的影响;

另一个例子

//请求模块var sendData = function (data, dealType, dom) {  ....  xhr.onload = function (event) {    if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {      dealData(xhr.responseText, dealType, dom);    } else {     //...    }    ....  }  ....};//适配响应数据var dealData(data, dealType, dom) {  ....  switch(dealType) {    case 'sug':    ....    createSug(data, dom);    case 'invalidate':    ....    createInvalidate(data, dom);  }  ....}//组件模块var createSug(data, dom) {  ....}var createInvalidate(data, dom) {  ....}
  • 在半成品方案情况下可以设置如此的责任链模式;
  • 耦合之间进行单元测试也更加简单;

职责链的优缺点

  • 优点
    • 解耦了请求发送者和多个接受者之间的关系;只需把请求传递给第一个节点;
    • 链中的节点对象可以灵活地拆分重组;
    • 可以手动设定起始节点;
  • 缺点
    • 由于不能确定每个节点都会正常处理;应该在链尾增加一个保底的接受者节点来处理即将离开链尾的请求;
    • 从性能考虑,应该避免过长的职责链带来的性能消耗;

转载于:https://www.cnblogs.com/jinkspeng/p/4582456.html

你可能感兴趣的文章
iOS 网易彩票-2框架搭建-代码重构
查看>>
python的模块
查看>>
3.6 Exercises
查看>>
jstl使用和jsp如何遍历传递过来的list数据
查看>>
reentrantlocklock实现有界队列
查看>>
Jquery
查看>>
数学(组合,容斥):COGS 1220. 盒子与球
查看>>
poj3041(最小顶点覆盖数,二分图匹配)+hdu1150+hdu1151
查看>>
Matplotlib新手上路(中)
查看>>
ALT+TAB切换时小图标的添加 界面透明 屏幕大小 竖行字体 进程信息
查看>>
js在IE和FF下的兼容性问题
查看>>
如何保证消息队列的可靠性传输?
查看>>
其他ip无法访问Yii的gii,配置ip就可以
查看>>
js创建对象
查看>>
有状态EJBBean和无状态的EJBBean
查看>>
设计模式的几种原则
查看>>
使用json格式输出
查看>>
border-image属性在chrome中的不同效果
查看>>
我对师生关系的思考
查看>>
php做的一个简易爬虫
查看>>