• 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中,由于函数是一等公民,策略类常常被函数替代而隐性使用策略模式;

    与状态模式

    • 都是在内部封装一个对象,然后通过返回的接口对象实现对象内部对象的调用;
    • 策略模式不需要管理状态,状态之间没有依赖关系,策略之间可以互相替换;在策略对象内部保存的是相互独立的算法;
  • 相关阅读:
    Failed to load config "react-app" to extend from.
    An unexpected error occurred: "expected workspace package to exist for "@babel/core"".
    写一个 LRU 缓存函数(#146)
    TERSUS笔记303-06末页
    TERSUS笔记302-08每页条数逻辑
    TERSUS笔记301-显示列表处理+序号+01共几条取值+08每页条数下拉菜单值设置+02共页数计算取值
    TERSUS笔记300-增加
    TERSUS笔记118-多表增删改查完整操作
    Java多线程之二(Synchronized)
    HashMap在JDK1.7中可能出现的并发问题
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4582444.html
Copyright © 2020-2023  润新知