03单例,策略

单例模式

  • 保证一个类只有一个实例,并提供一个访问他的全局访问点;

模拟单例实现

  • 传统方式:
var createDiv = (function(){
  var instance;
  var createDiv = function(html){
    if(instance)
      return instance;
    this.html = html;
    this.init();
    return instance = this;
  };
  createDiv.prototype.init = function() {
    var div = document.createElement('div');
    div.innerHTML = this.html;
    document.body.appendChild(div);
  };
  return createDiv;
})();
  • 代理实现:
var createDiv = function(html) {
  this.html = html;
  this.init();
};

createDiv.prototype.init = function() {
  var div = document.createElement('div');
  div.innerHTML = this.html;
  document.body.appendChild(div);
};

var proxyCreateDiv = (function(){
  var instance;
  return function(html) {
    if(instance)
      return instance;
    return new CreateDiv(html);
  }
})(); 

JS中的单例模式

  • 传统模式中单例对象从类中创建而来,但JS其实并无类;
  • 抓做单例模式核心:确保只有一个可全局访问的实例;可以用更符合JS的方式创建
  • 使用命名空间
    • 适当使用全局命名空间
    • 动态创建命名空间
var MyApp = {};
  
MyApp.namespace = function(name) {
  var parts = name.split('.'),
      current = MyApp;
  for(prop in parts) {
    if(!current[parts[prop]])
      current[parts[prop]] = {};
    current = current[parts[prop]];
  }
}
  • 使用闭包封闭私有变量
var user = (function() {
  var _name = 'jinks',
      _age = 23;
  return {  //对象返回
    getUserInfo: function() {
      return _name + ' ' + _age;
    }
  }
})();

惰性单例

  • 即只在需要的时候才创建的单例对象实例
  • 优化把创建实例对象和管理单例分开
/**
 * 点击创建|显示|隐藏div
 */
var getSingle = function (fn) {
  var result;
  return function() {
    return result || (result = fn.apply(this, arguments))  
  }
};

var createDiv = function(name, id) {
  var div = document.createElement('div');
  div.innerHTML = name;
  div.id = id;
  div.style.display = 'none';
  document.body.appendChild(div);
  return div;
};

var divChange = function(fn,name,id) {
  var div = fn(name,id);
  var display = div.style.display;
  div.style.display = display === 'none' ? 'block' : 'none';
};

divElem = {
  div1: getSingle(createDiv),
  div2: getSingle(createDiv)
};

document.getElementById('div1Btn').onclick = function () {
  divChange(divElem.div1,'div1','div1');
};
document.getElementById('div2Btn').onclick = function () {
  divChange(divElem.div2,'div2','div2');
};
  • 利用惰性单例也可以实现one()绑定事件的效果
var bindEvent = getSingle(function() {
  document.getElementById('click').onclick = function() {
    alert('click');
  }
  return true;
});

bindEvent();  //只在第一次时绑定
bindEvent();
bindEvent();

策略模式

  • 定义并封装一系列的算法,并且使他们可以互相替换
  • 一个基于策略模式的程序至少由两部分组成:
    • 策略类:封装了具体的算法,并负责具体的计算过程;
    • 环境类:接受请求后委托给某个策略类;

模拟策略实现

/**
 * 计算奖金
 */ 
//策略类
var performancsA = function () {}
performancsA.prototype.calculate = function(salary) {
  return salary * 3;
};
var performancsB = function () {}
performancsB.prototype.calculate = function(salary) {
  return salary * 4;
};
//环境类
var Bonus = function() {
  this.salary = null;
  this.strategy = null;
};
Bonus.prototype.setSalary = function(salary) {
  this.salary = salary;
};
Bonus.prototype.setStrategy = function(strategy) {
  this.strategy = strategy;
};
Bonus.prototype.getBouns = function() {
  return this.strategy.calculate(this.salary);
};


var bouns = new Bonus;
bouns.setSalary(10000);
bouns.setStrategy(new performancsA);
bouns.getBouns();//30000;
bouns.setStrategy(new performancsB);
bouns.getBouns();//40000;

JS中的策略模式

  • JS中函数也是对象
var strategies = {
 'A': function (salary) {
   return salary * 3; 
 },
 'B': function (salary) {
   return salary * 4;
 }
};

var calculateBonus = function(level, salary) {
  return strategies[level](salary);
};

calculateBonus('A', 10000);
calculateBonus('B', 10000);

实现缓动动画

//缓动算法
  var tween = {
    linear: function(t, b, c, d) { //已消耗的时间,原始位置,目标位置,持续总时间
      return c * t / d + b;
    },
    easeIn: function(t, b, c, d) {
      return c * (t /= d) * t + b;
    },
    strongEaseIn: function(t, b ,c ,d) {
      return c * (t /= d) * t * t * t * t + b;
    },
    strongEaseOut: function(t, b, c, d) {
      return c * ((t = t / d - 1) * t * t * t * t * t + 1) + b;
    },
    sineaseIn: function(t, b, c, d) {
      return c * (t /= d) * t * t + b;
    },
    sineaseOut: function(t, b ,c ,d) {
      return c * ((t = t /d - 1) * t * t + 1) + b;
    },

  };

  var Animate = function (elem) {
    this.elem = elem;
    this.startTime = 0;
    this.startPos = 0;
    this.endPos = 0;
    this.properrtName = null;
    this.easing = null;
    this.duration = null;
  };

  Animate.prototype.start = function (properrtName, endPos, duration, easing) {
    var self = this;
    self.startTime = +new Date;
    self.startPos = self.elem.getBoundingClientRect()[properrtName];
    self.properrtName = properrtName;
    self.endPos = endPos;
    self.duration = duration;
    self.easing = tween[easing];

    var timeId = setInterval(function() {
      if(self.step() === false)
        clearInterval(timeId);
    }, 20);
  };
  Animate.prototype.step = function() {
    var t = +new Date;
    if(t >= this.startTime + this.duration) {
      this.update(this.endPos);
      return false;
    }
    var pos = this.easing(t - this.startTime, this.startPos, this.endPos - this.startPos, this.duration);
    this.update(pos);
  };

  Animate.prototype.update = function(pos) {
    this.elem.style[this.properrtName] = pos + 'px';
  }

  var div = document.getElementById('div');
  var animate = new Animate(div);

  animate.start('left', 500, 1000, 'sineaseIn');

实现表单验证

  var InputStrategy = function () {
    var strategy = {
      notNull: function (value) {
        return /s+/.test(value) ? '请输入内容' : '';
      },
      number: function (value) {
        return /^[0-9]+(.[0-9]+)?$/.test(value) ? '' : '请输入数字';
      },
      phone: function (value) {
        return /^d{3}-d{8}$|^d{4}-d{7}$/.test(value) ? '' : '请输入数字';
      }
    }
    return {
      check: function (type, value) {
        value = value.replace(/^s+|s+$/g, '');
        return strategy[type] ? strategy[type](value) : '没有改类型的检验方法'
      },
      //添加策略
      addStrategy: function (type, fn) {
        strategy[type] = fn;
      }
    }
  }();

  //扩展
  InputStrategy.addStrategy('nickname', function (value) {
  	console.log(value);
    return /^[a-zA-Z]w{3,7}$/.test(value) ? '' : '请输入4-8位昵称'
  });
  console.log(InputStrategy.check('nickname', 'aaaa'));

优点

  • 利用组合、委托、多态等,有效避免多重条件选择
  • 对开放-封闭原则的支持
  • 重用性高
  • 组合和委托方式来替代继承
  • JS中,由于函数是一等公民,策略类常常被函数替代而隐性使用策略模式;

与状态模式

  • 都是在内部封装一个对象,然后通过返回的接口对象实现对象内部对象的调用;
  • 策略模式不需要管理状态,状态之间没有依赖关系,策略之间可以互相替换;在策略对象内部保存的是相互独立的算法;
原文地址:https://www.cnblogs.com/jinkspeng/p/4582444.html