建造者模式

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

解释

前面我们讨论过工厂方法模式,工厂方法模式主要用于创建某一类对象的实例或者创建某对象类簇,暴露出来的只是一个工厂方法的接口,使用这个接口的用户对实例的创建过程并不关心,他们所要做的只是调用工厂方法,然后获取相应的实例对象。

但是对于复杂对象,每个对象可能由很多个不同的部分组成,这些成员有各自的特性,可以相互之间互相组合,这样的需求情景下使用工厂方法模式就有些力不从心了。

这时候我们可以使用建造者模式,核心思想就是,通过封装的建造者对象,对象构建时的细节是可控的,通过对建造者参数控制,能够控制创建对象的细节。看下例:

var Human = function(param) {
  this.skill = param && param.skill || '保密'
  this.hobby = param && param.hobby || '保密'
}
Human.prototype = {
  getSkill: function() {
    return this.skill
  },
  getHobby: function() {
    return this.hobby;
  }
}

var Named = function(name){
  var that = this;
  (function(name, that){
    that.wholeName = name;
    that.firstName = name.substring(0, name.indexOf(' '))
    that.lastName = name.substring(name.indexOf(' '))
  })(name,that)
}
var Work = function(work) {
  var that = this;
  (function(work, that){
    switch(work){
      case 'code':
        that.work = "工程师"
        that.description="每天沉醉于编程"
        break;
      default:
        that.work = work;
        that.description = "对不起我们还不清楚您选择职位的相关描述"
        break;
    }
  })(work, that)
}
Work.prototype.changeWork = function(work) {
  this.work = work;
}

// 构建者类
var PersonBuilder = function(name, work) {
  var _person = new Human();
  name && (_person.name = new Named(name));
  work && (_person.work = new Work(work));
  return _person;
}

// 创建一个带有名字的对象
var personWithName = new PersonBuilder('Bright','code')
// 创建一个不带名字的对象
var personWithoutName = new PersonBuilder('', 'code')

上面的示例中,我们要创建的对象由三个部分组成,Human、Named、Work,构建这个对象时我们可以通过参数控制实现各个组成部分的组合情况,可以控制对象构建的细节

思考

设计模式知识一种思想,而不应该纠结于具体的实现,不同的示例会给出不同的实现,叫不叫Builder之类的名字也无所谓,关键时要理解设计模式的核心思想。在构建型设计模式中,我们关注的核心是对象的构建,什么时候应用什么样的构建对象的思想也要根据具体的业务场景来选择,而不是为了设计模式而设计,也不是仅仅套设计模式实例。