7

1. 简介

工厂模式的目的是为了创建对象,它通常在类或者类的静态方法中实现,具有以下目标:

  • 当创建相似对象时执行重复操作
  • 当编译时不知道具体类型的情况下,为工厂客户提供一个创建对象的接口

与创建型模式类似,工厂模式创建对象(视为工厂里的产品)时无需指定创建对象的具体类。

工厂模式定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

这个模式十分有用,尤其是创建对象的流程赋值的时候,比如依赖于很多设置文件等。并且,你会经常在程序里看到工厂方法,用于让子类类定义需要创建的对象类型。

2. 实现

一个简单的实现,使用IIFE:

var Car = (function () {
    var Car = function (model, year, miles) {
        this.model = model;
        this.year = year;
        this.miles = miles;
    };
    return function (model, year, miles) {
        return new Car(model, year, miles);
    };
})();

var tom = new Car("Tom", 2009, 20000);
var dudu = new Car("Dudu", 2010, 5000);

如果使用对象属性来实现:

var productManager = {};

productManager.createProductA = function() {
    this.prd = 'A'
    console.log('Product ' + this.prd);
}
productManager.createProductB = function() {
    this.prd = 'B'
    console.log('Product ' + this.prd);
}

productManager.factory = function(typeType) {
    return new productManager[typeType];
}

productManager.factory("createProductA");    // Product A
productManager.factory("createProductB");    // Product B

以下例子中的工厂方法接受在运行时以字符串形式指定的类型,然后创建并返回所请求类型的对象。

function CarMaker() {}

CarMaker.prototype.drive = function() {
  return `I have ${this.doors} doors!`
}

CarMaker.factory = function(type) {
  const constr = type
  if (typeof CarMaker[constr] !== 'function') {
    throw new Error(`${constr} doesnot exist`)
  }
  // 原型继承的方式使得原型继承父类
  if (typeof CarMaker[constr].prototype.drive !== 'function') {
    CarMaker[constr].prototype = new CarMaker()
  }
  return new CarMaker[constr]()
}

CarMaker.Compact = function() { this.doors = 4}
CarMaker.Convertible = function() { this.doors = 2}

const corolla = CarMaker.factory('Compact')
corolla.drive()    // "I have 4 doors!"

也可以把实际对象的创建工作放到原型中:

const Factory = function(type, content) {
  return (this instanceof Factory)
      ? new this[type](content)
      : new Factory(type, content)
}

Factory.prototype.Compact = function(content) { this.doors = 4}
Factory.prototype.Convertible = function(content) { this.doors = 2}

Factory.prototype.Compact.prototype.drive = function() {
  return `I have ${this.doors} doors!`
}

const corolla = Factory('Compact')
corolla.drive()    // "I have 4 doors!"

3. 总结

那么什么时候使用工厂模式呢,以下几种情景下工厂模式特别有用:

  • 对象的构建十分复杂
  • 需要依赖具体环境创建不同实例
  • 处理大量具有相同属性的小对象

什么时候不该用工厂模式:
不滥用运用工厂模式,有时候仅仅只是给代码增加了不必要的复杂度,同时使得测试难以运行下去。


本文是系列文章,可以相互参考印证,共同进步~

  1. JS 抽象工厂模式
  2. JS 工厂模式
  3. JS 建造者模式
  4. JS 原型模式
  5. JS 单例模式
  6. JS 回调模式
  7. JS 外观模式
  8. JS 适配器模式
  9. JS 利用高阶函数实现函数缓存(备忘模式)
  10. JS 状态模式
  11. JS 桥接模式
  12. JS 观察者模式

网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:
深入理解JavaScript系列(28):设计模式之工厂模式
《JS 模式》
《Javascript 设计模式》 - 张荣铭

PS:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~

另外可以加入「前端下午茶交流群」微信群,长按识别下面二维码即可加我好友,备注加群,我拉你入群~


SHERlocked93
6.4k 声望4.9k 粉丝