js设计模式(二)-工厂模式

11

前言

设计模式填坑系列,紧接前文(距离上次写笔记又过去了一个多月,我也不知道怎么加班加着加着就一个月了-_-!)

正文

定义

工厂模式是指提供一个创建对象的接口而不保留具体的创建逻辑,可以根据输入类型创建对象。让子类自行决定实例化哪一种工厂类,实际的创建对象过程在子类中进行。在创建相似子类的时候,执行重复操作。(觉得我说的太抽象没关系,马上就到举例子环节)

具体实现

前面的描述可能还是稍显抽象,举个游戏里面的例子,我们需要实现一个生产游戏角色的RoleMaker工厂,达到以下目的:

var warrior = RoleMaker.factory('warrior')//生产一个战士
var mage = RoleMaker.factory('mage')//生产一个法师
var priest = RoleMaker.factory('priest')//生产一个牧师
warrior.introduce()// 输出 '我是一个战士,我的特长是近战'
mage.introduce()// 输出 '我是一个法师,我的特长是魔法'
priest.introduce()// 输出 '我是一个牧师,我的特长是治疗'

在这里,我们可以看到形如var warrior = RoleMaker.factory('warrior')的语句,就是使用RoleMaker工厂生产了一个战士的过程,这里的战士法师牧师都是角色的一个子类。

接下来就是如何实现上面的RoleMaker类,最核心的思想还是原型链继承(忘记的同学请自行补课,磨刀不误砍柴工),具体的实现代码如下:

  //父类
  function RoleMaker() {
    // 这里是父类的属性
  }

  RoleMaker.prototype.introduce = function () {
    return '我是一个' + this.type + ',我的特长是' + this.specialty
  }

  //工厂方法
  RoleMaker.factory = function (type) {
    var role;
    // 这里我们直接把子类构造函数都保存在父类的静态属性中,这样的好处是不污染全局命名空间,同时方便查找。实际上当然也可以直接用`switch-case`实现
    if (typeof (RoleMaker[type]) !== "function") {
      //对未指定子类的处理,这里是直接抛出错误,也可以为未指定类型做默认值处理
      throw {
        name: 'Error',
        message: type + 'does not exist'
      }
    }
    if (typeof (RoleMaker[type].prototype.introduce !== "function")) {
      // 判断是否已经实现继承,注意只继承一次,当然由于只是原型链继承这里判断条件也可以用`RoleMaker[type].constructor===RoleMaker`
      RoleMaker[type].prototype = new RoleMaker()
    }

    role = new RoleMaker[type]() //实例化,也就是实际创建对象的过程
    return role
  }

  // 每个子类的构造函数
  RoleMaker.warrior = function () {
    this.type = "战士",
      this.specialty = "近战"
  }
  RoleMaker.mage = function () {
    this.type = "法师",
      this.specialty = "魔法"
  }
  RoleMaker.priest = function () {
    this.type = "牧师",
      this.specialty = "治疗"
  }

以上代码比较简单,来回顾下前文说道的几个特点:

  1. 使用者只需要知道特定子类的名称就可以直接生产对应的子类,无需知道具体实现逻辑
  2. 实际的创建对象过程在子类中进行
  3. 在创建相似子类的时候,执行重复操作(每个子类只做一次的继承)

补充一个实例

实际上,js的Object()函数,就很符合工厂模式的特征:

var n = Object(1)
n.constructor === Number
var s = Object('1')
n.constructor === String
var b = Object(true)
n.constructor === Boolean

小结

自我感觉设计模式系列由于还是处于学习阶段,实践经验相对较少,所以写起来还是偏向于读书笔记类,所以可能有很多地方都显得粗糙。权当做先占个坑,等后续有更深入理解再回来补上。
然后惯例感谢之前的热心读者,尤其是为我指出错误的小伙伴。
然后依然是每次都一样的结尾,如果内容有错误的地方欢迎指出;如果对你有帮助,欢迎点赞和收藏,转载请征得同意后著明出处,如果有问题也欢迎私信交流,主页添加了邮箱地址~溜了


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

say_hello_world · 2018年08月03日

你实现继承的时候 RoleMaker[type].prototype = new RoleMaker() 没有将子类的prototype.constructor指向子类自己的构造函数 应该加一句 RoleMaker[type].prototype.constructor = RoleMaker[type];

回复

bug之所措 · 9月12日

你们代码都没跑一次的吗?????????
var warrior = RoleMaker.factory('warrior')//生产一个战士
这句代码不会报错吗??????我????????

回复

0

不好意思,为了叙述方便,先把目标代码提前了,想跑完整代码 要配上后面一段的函数类定义和方法声明,文章有描述,可能不太明显。

安歌 作者 · 9月12日
0

@安歌 小编,我肯定把你后面的定义放在前面定义好再执行这段代码啊···我晕 = =
你确定你的代码不会报错吗??你的factory是定义在了RoleMaker.prototype的上面,但是你使用的时候你是RoleMaker.factory这样使用,肯定不行啊,定义在了原型链上面,你要么就new RoleMaker().factory,要么你就放在函数上面,RoleMaker.factory这样定义。。。我说的应该没错吧?

bug之所措 · 9月12日
0

@bug之所措 对,introducefactory 两个方法的定义位置写错了,已更正, 感谢指出。

安歌 作者 · 9月12日
载入中...