Skip to content

设计模式

设计模式的代码简述

单例模式

单例在编程实战中存在大量的应用,比如说弹窗。

js
{
  const Singleton = function(name) {
    this.name = name
    this.instance = null
  }
  Singleton.prototype.getName = function() {
    console.log(this.name)
  }
  Singleton.getInstance = function() {
    if (!this.singleton) {
      this.instance = new Singleton(name)
    }
    return this.instance
  }
  var a = Singleton.getInstance('sing1')
  var b = Singleton.getInstance('sing2')
}

策略模式

一个计算工资的例子

js
var performanceS = function(){};
performanceS.prototype.calculate = function(salary) {
  return salary * 4
}
var performanceA = function(){};
performanceA.prototype.calculate = function(salary) {
  return salary * 3
}
var performanceB = function(){}
performanceB.prototype.calculate = function(salary) {
  return salary * 2
}

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.getBonus = function(){
  return this.strategy.calculate( this.salary );
};

适用于JavaScript的策略模式

js
var strategies = {
  "S": function(salary) {
    return salary * 4;
  },
  "A": function(salary) {
    return salary * 3
  },
  "B": function(salary) {
    return salary * 2
  }
}
var calculateBonus = function( level, salary ){ 
  return strategies[level](salary);
};
console.log(calculateBonus("S", 2000)) // 8000
console.log(calculateBonus("A", 1000)) // 3000

代理模式

  • 虚拟代理
js
var myImage = (function(){
  var imgNode = document.createElement('img')
  document.body.appendChild(imgNode)
  return {
    setSrc: function(src) {
      imgNode.src = src
    }
  }
})()

var proxyImage = (function() {
  var img = new Image
  img.onload = function() {
    myImage.setSrc(this.src)
  }
  return {
    setSrc: function(src) {
      myImage.setSrc('加载中图片');
      img.src = src;
    }
  }
})()
proxyImage.setSrc('实际的图片');
  • 缓存代理
js
const proxyMulti = function() {
  const cache = {}
  return function() {
    const args = Array.prototype.join.call( arguments, ',' );
    if (args in cache) {
      return cache[args]
    }
    return cache[args] = multi.apply( this, arguments );
  }
}
function multi() {
  var a = 1
  for(var i = 0; l = arguments.length; i++) {
    a = a * arguments[i]
  }
  return a
}

迭代器模式

可以理解为迭代器模式就是对同一问题的不同参数的反复迭代过程。

内部迭代

实现一个 each 函数,each 函数接受 2 个参数,第一个为被循环的数组,第 二个为循环中的每一步后将被触发的回调函数。

js
var each = function( ary, callback ){
  for ( var i = 0, l = ary.length; i < l; i++ ){
    callback.call( ary[i], i, ary[ i ] );
  }
}
each( [ 1, 2, 3 ], function( i, n ){ 
  alert ( [ i, n ] );
});

外部迭代器

判断 2 个数组里元素的值是否完全相等

js
var Iterator = function(obj) {
  var current = 0;
  var next = function() {
    current += 1
  }
  var isDone = function() {
    return current >= obj.length
  }
  var getCurrentItem = function() {
    return obj[current]
  }
  return {
    next,
    isDone,
    getCurrentItem
  }
}

var compare = function(iterator1, iterator2) {
  while(!iterator1.isDone() && !iterator2.isDone()) {
    if(iterator1.getCurrentItem() !== iterator2.getCurrentItem()) {
      throw new Error ( 'iterator1 和 iterator2 不相等' );
    }
    iterator1.next();
    iterator2.next();
  }
  alert ( 'iterator1 和 iterator2 相等' );
}

发布-订阅模式

基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知。

js
class Pubsub {
  constructor() {
    this.handlers = {}
  }

  addEventListener(type, handler) {
    if(!(type in this.handlers)) {
      this.handlers[type] = []
    }
    this.handlers[type].push(handler)
  }

  dispatchEvent(type, ...params) {
    if(!(type in this.handlers)) {
      return new Error("未注册该事件")
    }
    this.handlers[type].forEach(handler => {
      handler(...params)
    })
  }

  removeEventListers(type, handler) {
    if(!(type in this.handlers)) {
      return new Error("无效事件")
    }
    if(!handler) {
      delete this.handlers[type]
    } else {
      const idx = this.handlers[type].findIndex(ele => ele === handler)
      if(idx === undefined) {
        return new Error("无该绑定事件")
      }
      this.handlers[type].splice(index, 1)
      if(this.handlers[type].length === 0) {
        delete this.handlers[type]
      }
    }
  }
}

观察者模式

一个对象(称为subject)维持一系列依赖于它的对象(称为observer),将有关状态的任何变更自动通知给它们(观察者)。

js
/**
 * 观察者模式组件
 * @author  wilton
 */
define(function(require, exports, module) {

 function ObserverList () {
  this.observerLists = [];
 }

 // 添加观察者对象
 ObserverList.prototype.add = function(obj){

  // 保证observer的唯一性
  if (this.observerLists.indexOf(obj) != -1) return this.observerLists;
  return this.observerLists.push(obj);
 },

 // 清空观察者对象
 ObserverList.prototype.empty = function(){
  this.observerLists = [];
 },

 // 计算当前的观察者数量
 ObserverList.prototype.count = function(){
  return this.observerLists.length;
 },

 // 取出对应编号的观察者对象
 ObserverList.prototype.get = function(index){
  if (index > -1 && index < this.observerLists.length) {
   return this.observerLists[index];
  }
 },

 // 指定位置上插入观察者对象
 ObserverList.prototype.insert = function(obj,index){
  var pointer = -1;

  if (index === 0) {
   this.observerLists.unshift(obj);
   pointer = index;
  } else if (index === this.observerLists.length) {
   this.observerLists.push(obj);
   pointer = index;
  } else {
   this.observerLists.splice(index, 0, obj);
   pointer = index;
  }

  return pointer;
 },

 // 查找观察者对象所在的位置编号
 ObserverList.prototype.indexOf = function(obj, startIndex){
  var i = startIndex || 0, pointer = -1;

  while (i < this.observerLists.length) {
   if (this.observerLists[i] === obj) {
    pointer = i;
    break;
   }
   i++;
  }

  return pointer;
 },

 // 移除指定编号的观察者
 ObserverList.prototype.removeIndexAt = function(index){
  var temp = null;
  if (index === 0) {
   temp = this.observerLists.shift();
  } else if (index === this.observerLists.length) {
   temp = this.observerLists.pop();
  } else {
   temp = this.observerLists.splice(index, 1)[0];
  }

  return temp;
 }

 // 定义目标类
 function Subject(){
  this.observers = new ObserverList();
 }

 // 添加观察者
 Subject.prototype.addObserver = function(observer){
  this.observers.add(observer);
 }

 // 移除观察者
 Subject.prototype.removeObserver = function(observer){
  this.observers.removeIndexAt(this.observers.indexOf(observer, 0));
 }

 // 通知观察者
 Subject.prototype.notify = function(params){
  var observersCount = this.observers.count();

  for(var i = 0; i < observersCount; i++){
   this.observers.get(i).update(params);
  }
 }

 function Observer(){

  // 定义观察者内容更新事件
  this.update = function(){}
 }

 module.exports = {
  Observer: Observer,
  Subject: Subject,

  // 对象扩展
  extend: function(obj, extension){
   for (var key in obj) {
    extension[key] = obj[key];
   }
  }
 }; 
});

img

命令模式

js
var command1 = {
  execute: function(){
    console.log(1);
  }
};
var command2 = {
  execute: function(){
    console.log(2);
  }
}
var command3 = {
  execute: function(){
    console.log(3);
  }
}
var command = function() {
  return {
    commandList: [],
    add: function(command) {
      this.commandList.push(command)
    },
    execute: function(command) {
      for(var i = 0,commands = this.commandsList.length; i < commands; i+=1) {
        this.commandsList[i].execute();
      }
    }
  }
}

img

Released under the MIT License.