设计模式

70 阅读3分钟

设计模式

单例模式

定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 单例模式的核心是确保只有一个实例,并提供全局访问。

var Singleton = function(name) {
  this.name = name;
  this.instance = null;
}
Singleton.prototype.getName = function() {
  altert(this.name)
}
Singleton.getInstance = function(name) {
  if (!this.instance) {
    this.instance = new Singleton(name)
  }
  return this.instance;
}
var a = Singleton.getInstance('sven1')
var b = Singleton.getInstance('sven2')
// a === b

策略模式

俗话说,条条大陆通罗马,很多时候也有多种途径到达同一个目的地。比如我们要去某个地方旅游,可以坐火车、飞机、大巴

定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

例如计算奖金(根据绩效和基础工资)

const strategies = {
  S: (salary) => salary * 4,
  A: (salary) => salary * 3,
  B: (salary) => salary * 2,
}
// 入参(绩效, 基础工资)
const calculateBonus = (level, salary) => {
  return strategies[level](salary)
}
console.log(calculateBonus('S', 20000)) // 80000
console.log(calculateBonus('A', 10000)) // 30000

代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问

var Flower = function() {}
var xiaoming = {
  sendFlower: function(target) {
    var flower = new Flower()
    target.receiveFlower(flower);
  }
}
var B = {
  receiveFlower: function(flower) {
    A.receiveFlower(flower)
  }
}
var A = {
  receiveFlower: function(flower) {
    console.log('收到花'+flower)
  }
}
xiaoming.sendFlower(B)
var Flower = function() {}
var xiaoming = {
  sendFlower: function(target) {
    var flower = new Flower()
    target.receiveFlower(flower);
  }
}
var B = {
  receiveFlower: function(flower) {
    A.listenGoodMood(function() {
      A.receiveFlower(flower)
    })
  }
}
var A = {
  receiveFlower: function(flower) {
    console.log('收到花'+flower)
  },
  listenGoodMood: function(fn) {
    settTmeout(function() {
      fn()
    }, 10000)
  }
}
xiaoming.sendFlower(B)
// 保护代理
var Flower = function() {}
var xiaoming = {
  sendFlower: function(target) {
    target.receiveFlower();
  }
}
var B = {
  receiveFlower: function(flower) {
    A.listenGoodMood(function() {
      var flower = new Flower();
      A.receiveFlower(flower)
    })
  }
}
var A = {
  receiveFlower: function(flower) {
    console.log('收到花'+flower)
  },
  listenGoodMood: function(fn) {
    settTmeout(function() {
      fn()
    }, 10000)
  }
}
xiaoming.sendFlower(B)
var myImage = (funcrion() {
  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('/loading.gif')
      img.src = src
    }
  }
})()
proxyImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 内部迭代器:内部已经定义好了迭代规则,它完全接手整个迭代过程,外部只需要一次初始调用 外部迭代器必须显示地请求迭代下一个元素

// 内部迭代器
var each = function(ary, callback) {
  for(var i = 0, l = ary.length; i < 1; i++) {
    callback.call(ary[i], i, ary[i])
  }
}
each([1, 2, 3], function(i n) {
  alert([i, n])
})
// 外部迭代器
var Iterator = function(obj) {
  var current = 0;
  var next = function() {
    current += 1
  }
  var isDone = function() {
    return current >= obj.length
  }
  var getCurrItem = function() {
    return obj[current]
  }
  return {
    next: next,
    isDone: isDone,
    getCurrItem: isCurrItem
  }
}
var compare = function(iterator1, iterator2) {
  while(!iterator1.isDone && !iterator2.isDone()) {
    if(iterator1.getCurrItem() !== iterator2.getCurrItem()) {
      throw new Error('iterator1和iterator2不相等')
    }
    iterator1.next();
    iterator2.next();
  }
  altert('iterator1和iterator2相等')
}

命令模式

命令模式指的是一个执行某些特定事情的指令

var button1 = document.getElementById('button1')
var button2 = document.getElementById('button2')
var button3 = document.getElementById('button3')

var bindClick = function(button, func) {
  button.onclick =ffunc;
}
var MenuBar = {
  refresh: function() {
    console.log('刷新菜单')
  }
}
var SubMenu = {
  add: funciotn() {
    console.log('增加子菜单')
  },
  del: function() {
    console.log('删除子菜单')
  }
}
bindClick(button1, MenuBar.refresh)
bindClick(button2, MenuBar.add)
bindClick(button3, MenuBar.del)

适配器模式

适配器模式的作用是解决两个软件实体间的接口不兼容的问题。

var googleMap = {
  show: function() {
    console.log('谷歌地图')
  }
}
var baiduMap = {
  display: function() {
    console.loog('百度地图')
  }
}
var baiduMapAdapter = {
  show: baiduMap.display()
}
renderMap(googleMap)
renderMap(baiduMapAdapter)

设计原则和编程技巧

单一职责原则

单一职责原则:一个类应该仅有一个引起它变化的原因 代理模式

// 不用代理
var myImage = (function() {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode)
  var img = new Image;
  img.onload = function(src) {
    setSrc: function(src) {
      imgNode.src = '/loading.gif';
      img.src = src
    }
  }
})()
MyImage.setSrc('http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg')
// 代理
// myImage负责往页面中添加img标签
var myImage = (funcrion() {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode);
  return {
    setSrc: function(src) {
      imgNode.src = src
    }
  }
})()
// proxyImage负责预加载图片,并在预加载完成之后把请求体交给本体myImage
var proxyImage = (function() {
  var img = new Image;
  img.onload = function() {
    myImage.setSrc(this.src);
  }
  return {
    setSrc: function(src) {
      myImage.setSrc('/loading.gif')
      img.src = src
    }
  }
})()
proxyImage.setSrc( 'http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

迭代器模式

// 反例
var appendDiv = function(data) {
  for(var i = 0, l = data.length; i < l; i ++) {
    var div = document.createElement('div');
    div.innerHTML = data[i];
    document.body.appendChild(div)
  }
}
appendDiv([1, 2, 3, 4, 5])

var each = funciton(obj, callback) {
  var value,
  i = 0,
  length = obj.length,
  isArray = isArray(obj);
  if (isArray) {
    for(; i < length; i ++) {
      callback.call(obj[i], i, obj[i])
    }
  } else {
    for(i in obj) {
      value = callback.call(onj[i], i, obj[i])
    }
  }
}
var appendDiv = function(data) {
  each(data, function(i, n) {
    var div = document.createElement('div')
    div.innerHTML = n;
    document.appendChild(div)
  })
}
appendDiv([1, 2, 3, 4, 5])
appendDiv({a: 1, b: 2, c: 3, d: 4, e: 5})

单例模式

// 创建登录浮窗(不用设计模式)
var createLoginLayer = (function() {
  var div;
  return function() {
    if (!div) {
      div = document.createElement('div');
      div.innerHtml = '我是登录浮窗'
      document.body.appendChild(div);
    }
    return div;
  }
})()
// 管理单例的职责和创建登录浮窗的指责分开封装
var getSingle = function(fn) {
  var result;
  return function() {
    return result || (result = fn.apply(this, arguments))
  }
}
var createLoginLayer = function() {
  div = document.createElement('div');
  div.innerHtml = '我是登录浮窗'
  document.body.appendChild(div);
  return div;
}
var createSingleLoginLayer = getSingle(createLoginLayer)
createSingleLoginLayer();
createSingleLoginLayer();