Skip to content

《JavaScript 设计模式》创建型设计模式

简单工厂模式

由一个工厂对象决定创建某种产品对象的实例,主要用来创建同一类对象

多个类由一个 Factory 控制创建

js
//警示框类
var LoginAlert = function(text) {
  this.content = text
}
LoginAlert.prototype.show = function() {
  console.log('显示警告框')
}
//确认框类
var LoginConfirm = function(text) {
  this.content = text
}
LoginConfirm.prototype.show = function() {
  console.log('显示确认框')
}
//提示框类
var LoginPrompt = function(text) {
  this.content = text
}
LoginPrompt.prototype.show = function() {
  console.log('显示提示框')
}
//登录模块工厂
var PopFactory = function(name) {
  switch (name) {
    case 'alert':
      return new LoginAlert('显示警告框')
    case 'confirnm':
      return new LoginConfirm('显示确认框')
    case 'prompt':
      return new LoginPrompt('显示提示框')
  }
}
//使用示例
var oAlert = new PopFactory('alert')
console.log(oAlert) //LoginAlert { content: undefined }
console.log(oAlert.content) //显示警告框
oAlert.show() //显示警告框

创建一个新对象然后包装增强

js
function createPop(type, text) {
  var o = new Object()
  o.content = text
  o.show = function() {
    // 显示方法
  }
  if (type == 'alert') {
    //警示框差异部分
    console.log('警示: ' + text)
  }
  if (type == 'prompy') {
    //提示框差异部分
    console.log('提示: ' + text)
  }
  if (type == 'confirm') {
    //确认框差异部分
    console.log('确认: ' + text)
  }
  return o
}
var userNameAlert = createPop('alert', '用户名只能是26个字母和数字')

工厂方法模式

  • 将实际创建对象的工作推迟到子类中

  • 将创建对象的基类放在工厂方法累的原型中

js
//安全模式创建的工厂类
var Factory = function(type, content) {
  if (this instanceof Factory) {
    var s = new this[type](content)
    return s
  } else {
    return new Factory(type, content)
  }
}
//学科类工厂: 在工厂原型中设置创建所有类型数据对象的基类
Factory.prototype = {
  Java: function(content) {
    this.content = content //将内容保存在content里面,以备后用
    ;(function(content) {
      //创建对象时,通过闭包直接执行,将内容按需求的样式插入到页面内
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.color = 'green'
      document.getElementById('container').appendChild(div)
    })(content)
  },
  JavaScript: function(content) {
    this.content = content
    ;(function(content) {
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.color = 'pink'
      document.getElementById('container').appendChild(div)
    })(content)
  },
  UI: function(content) {
    this.content = content
    ;(function(content) {
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.border = '1px solid red'
      document.getElementById('container').appendChild(div)
    })(content)
  },
  PHP: function(content) {
    this.content = content
    ;(function(content) {
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.color = 'yellow'
      div.style.background = 'red'
      document.getElementById('container').appendChild(div)
    })(content)
  },
}

抽象工厂模式

通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创某一类的实例

  • 实现子类继承父类的方法
js
//创建抽象工厂方法
var VehicleFactory = function(subType, superType) {
  //判断抽象工厂中是否有该抽象类
  if (typeof VehicleFactory[superType] === 'function') {
    function F() {} //缓存类
    F.prototype = new VehicleFactory[superType]() //继承父类属性和方法
    subType.constructor = subType //将子类的constructor指向子类
    subType.prototype = new F() //子类原型继承父类
  } else {
    throw new Error('未创建该抽象类!') //不存在该抽象类时抛出错误
  }
}
//小汽车抽象类
VehicleFactory.Car = function() {
  this.type = 'car'
}
VehicleFactory.Car.prototype = {
  getPrice: function() {
    return new Error('抽象方法不能调用!')
  },
  getSpeed: function() {
    return new Error('抽象方法不能调用!')
  },
}
//公交车抽象类
VehicleFactory.Bus = function() {
  this.type = 'bus'
}
VehicleFactory.Bus.prototype = {
  getPrice: function() {
    return new Error('抽象方法不能调用!')
  },
  getPassengerNum: function() {
    return new Error('抽象方法不能调用!')
  },
}
//货车抽象类
VehicleFactory.Trunk = function() {
  this.type = 'trunk'
}
VehicleFactory.Trunk.prototype = {
  getPrice: function() {
    return new Error('抽象方法不能调用!')
  },
  getTrainload: function() {
    return new Error('抽象方法不能调用!')
  },
}
//宝马汽车子类
var BMW = function(price, speed) {
  this.price = price
  this.speed = speed
}
//抽象工厂实现对Car抽象类的继承
VehicleFactory(BMW, 'Car')
BMW.prototype.getPrice = function() {
  return this.price
}
BMW.prototype.getSpeed = function() {
  return this.speed
}
//兰博基尼汽车子类
var Lamborghini = function(price, speed) {
  this.price = price
  this.speed = speed
}
VehicleFactory(Lamborghini, 'Car')
Lamborghini.prototype.getPrice = function() {
  return this.price
}
Lamborghini.prototype.getSpeed = function() {
  return this.speed
}
//宇通汽车子类
var YUTONG = function(price, speed) {
  this.price = price
  this.speed = speed
}
VehicleFactory(YUTONG, 'Car')
YUTONG.prototype.getPrice = function() {
  return this.price
}
YUTONG.prototype.getSpeed = function() {
  return this.speed
}
//奔驰汽车子类
var BenzTrunk = function(price, trainLoad) {
  this.price = price
  this.trainLoad = trainLoad
}
VehicleFactory(BenzTrunk, 'Trunk')
BenzTrunk.prototype.getPrice = function() {
  return this.price
}
BenzTrunk.prototype.getTrainload = function() {
  return this.price
}
// 测试示例
var trunk = new BenzTrunk(100000000, 1000)
console.log(trunk.getPrice()) //100000000
console.log(trunk.type) //trunk

建造者模式

将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示

  • 注重的是创建细节
  • 创建的是一个复合对象
js
//创建一个Human类
var Human = function(param) {
  this.skill = (param && param.shill) || '保密'
  this.hobby = (param && pram.hobby) || '爱好'
}
Human.prototype = {
  getSkill: function() {
    return this.shill
  },
  getHobby: function() {
    return this.hobby
  },
}
//实例化创建的姓名类
var Named = function(name) {
  var oThis = this
  ;(function(name, oThis) {
    oThis.wholeName = name
    if (name.indexOf(' ') > -1) {
      oThis.FirstName = name.slice(0, name.indexOf(' '))
      oThis.secondName = name.slice(name.indexOf(' '))
    }
  })(name, oThis)
}
//实例化创建的工作类
var Work = function(work) {
  var oThis = this
  ;(function(work, oThis) {
    switch (work) {
      case 'code':
        oThis.work = '工程师'
        oThis.workDescript = '每天沉溺于编程'
        break
      case 'UI':
        oThis.work = '设计师'
        oThis.workDescript = '想象力无比丰富'
        break
      case 'UE':
        oThis.work = '设计'
        oThis.workDescript = '设计更似一种艺术'
        break
      case 'teach':
        oThis.work = '教师'
        oThis.workDescript = '分享是一种快乐'
        break
      default:
        oThis.work = work
        oThis.workDescript = '抱歉,还未找到您所选择的职位的描述'
    }
  })(work, oThis)
}
//更改期望的职位
Work.prototype.changeDescript = function(work) {
  this.work = work
}
//添加对职位的描述
Work.prototype.changeDescript = function(sentence) {
  this.workDescript = sentence
}

//创建完整的对象
var Person = function(name, work) {
  var person = new Human() //创建应聘者缓存对象
  person.name = new Named(name) //创建应聘者姓名解析对象
  person.work = new Work(work) //创建应聘者期望职位
  return person //返回应聘者对象
}
var person = new Person('Cynthia xie', 'code')
console.log(person.skill) //保密
console.log(person.name.FirstName) //Cynthia
console.log(person.work.work) //工程师
console.log(person.work.workDescript) //每天沉溺于编程
person.work.changeDescript('更改职位描述')
console.log(person.work.workDescript) //更改职位描述

原型模式

用原型实例指向创建对象的类,适用于创建新的对象的类共享原型对象的属性及方法

将可复用的、可共享的、消耗大的的从基类中提取出来放在其原型中,然后子类通过组合继承或者寄生组合式继承将方法和属性继承下来

js
//图片轮播类
var LoopImages = function(imgAttr, container) {
  this.imgesArray = imgAttr
  this.container = container
  // this.createImage = function(){};
  // this.changeImage = function(){};
}
LoopImages.prototype = {
  createImage: function() {
    console.log('LoopImages createImage function')
  },
  changeImage: function() {
    console.log('LoopImages changeImage function')
  },
}

//上下滑动切换
var SlideLoopImg = function(imgAttr, container) {
  LoopImages.call(this, imgAttr, container)
}
SlideLoopImg.prototype = new LoopImages()
SlideLoopImg.prototype.changeImage = function() {
  console.log('SlideLoopImg changeImage function')
}
//渐隐切换类
var FadeLoopImg = function(imgAttr, container, arrow) {
  LoopImages.call(this, imgAttr, container)
  this.arrow = arrow
}
FadeLoopImg.prototype = new LoopImages()
FadeLoopImg.prototype.changeImage = function() {
  console.log('FadeLoopImg changeImage function')
}

var fadeImg = new FadeLoopImg(['1.jpg', '2.jpg', '3.jpg', '4.jpg'], 'slide', [
  'left.jpg',
  'right.jpg',
])

//测试用例
console.log(fadeImg.container) //slide
fadeImg.changeImage() //FadeLoopImg changeImage function

//原型的拓展:子类和父类的额实例对象都会被继承下来
LoopImages.prototype.getImageLength = function() {
  return this.imgesArray.length
}
LoopImages.prototype.getContainer = function() {
  return this.container
}
console.log(fadeImg.getImageLength()) //4
console.log(fadeImg.getContainer()) //slide

不使用new

js
//基于已经缓存的模板对象克隆出新对象的模式
function prototypeExtend() {
  var F = function() {} //缓存类,为实例化返回对象临时创建
  var args = arguments,
    i = 0,
    len = args.length
  for (; i < len; i++) {
    for (var j in args[i]) {
      //遍历每个模板对象中的属性
      F.prototype[j] = args[i][j] //将这些属性复制到缓存类原型中
    }
  }
  return new F() //返回缓存类的一个实例
}
var penguin = prototypeExtend(
  {
    speed: 20,
    swim: function() {
      console.log('游泳速度 ' + this.speed)
    },
  },
  {
    run: function(speed) {
      console.log('奔跑速度 ' + speed)
    },
  },
  {
    jump: function() {
      console.log('跳跃动作')
    },
  }
)

penguin.swim() //游泳速度 20
penguin.run(10) //游泳速度 10
penguin.jump() //跳跃动作

单例模式

只允许实例化一次的对象类

  • 规划命名空间

管理静态变量

js
var Conf = (function() {
  var conf = {
    MAX_NUM: 100,
    MIN_NUM: 1,
    COUNT: 1000,
  }
  return {
    get: function(name) {
      return conf[name] ? conf[name] : null
    },
  }
})()
var count = Conf.get('COUNT')
console.log(count) // 1000

惰性单例

js
//惰性载入单例
var LazySingle = (function() {
  var instance = null //单例实例引用
  function Single() {
    //单例
    /*在这里定义使用属性和方法*/
    return {
      publicMethod: function() {},
      publicProperty: '1.0',
    }
  }
  return function() {
    //获取单例对象的借口
    if (!instance) {
      //如果是创建单例将创建单例
      instance = Single()
    }
    return instance //返回单例
  }
})()
console.log(LazySingle().publicProperty) //结果: 1.0