js设计模式——工厂模式

300 阅读3分钟

1、简易工厂模式

简易工厂模式又叫静态工厂方法,由一个工厂对象来决定创建某一类产品对象类的实例,主要用于创建同一类对象 《JavaScript设计模式 张容铭》

1-1、如果类太多,尽量提供一个

下面定义各种汽车类

function Car(color) {
  this.color = color
  this.type = 'car'
}
Car.prototype = {
  //car类身上的方法
}
function Truck(color) {
  this.color = color
  this.info = '这是卡车的类'
}
Truck.prototype = {
  //Truck类上的方法。
}

此时使用时想要生成不同的汽车时,就需要去找到不同的类进行 new 的操作。上面只是两个不同类, 如果我们需要有很多种类型,则会出现一个很明显的问题,全局中暴露出过多的函数,在一些大型项目中增加了命名冲突的可能性,同时每次创建不同的汽车时都需要去找到生成对应汽车的类。因此可以进行处理如下。

function Vehicle(type,color) {
  function Car(color) {
    this.color = color
    this.type = 'car'
  }
  Car.prototype = {
    //car类身上的方法
  }
  function Truck(color) {
    this.color = color
    this.info = '这是卡车的类'
  }
  Truck.prototype = {
    //Truck类上的方法。
  }
  switch(type){
    case 'Car':return new Car(color);
    case 'Truck':return new Truck(color);
    default:throw new Error(`还没有创建${type},先去创建一个吧`)
  }
}

此时避免了全局变量过多的危害,同时我们不需要去过多的关注每一个类,只需要传入不同的type,Vehicle就会帮我们返回对应类的实例化对象。同时,对于没有的类型抛出错误。有一个友好的提示。

1-2、一个对象也可以代替多个类

function Vehicle(type,color) {
  var o = new Object()
  o.color = color
  if(type==='Car'){
    o.type = 'Car'
    o['方法名'] = function(){
      //Car 的方法
    }
  }
  if(type==='Truck'){
    this.info = '这是卡车的类'
    o['方法名'] = function(){
      //Truck的方法
    }
  }
  return o
}

1-1和1-2的区别 第一种是通过对不同的类的实例化对象创建,第二种是通过创建一个新对象,然后包装增强其属性和功能来实现,第一种方法如果调用的这些类是继承同一父类,那么他们父类原型上的方法是可以公用的,但是通过第二种方法,每次创建都是一个新的对象,他们的方法不能共用

2、工厂方法模式

通过对产品的抽象使其创建业务主要负责用于创建多类产品的实例

如根据不同的语言生成不同背景和字体颜色的需求处理

function JobFactory(type, content) {
  function Java(content) {
    this.content = content
    (function(content) {
      var dev = document.createElement('div')
      div.innerHTML = content
      div.style.color = 'red'
      document.getElementById('container').appendChild(div)
    })(content)
  }
  function Php(content) {
    this.content = content
    (function(content) {
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.color = 'red'
      div.style.background = '#EEE'
    })(content)
  }
  function JavaScript(content) {
    this.content = content
    (function(content) {
      var div = document.createElement('div')
      div.innerHTML = content
      div.style.color = '#fff'
      div.style.background = '#000'
    })(content)
  }
  switch (type) {
    case 'Java':
      return new Java(content);
    case 'Php':
      return new Php(content);
    case 'JavaScript':
      return new JavaScript(content);
      default:throw new Error(`还没有创建${type},先去创建一个吧`)
  }
}

对于上面的方法,每次新添加一个类时,不仅需要添加一个类,同时还要在switch中添加case判断。因此我们可以看一下安全的工厂方法模式,如下:

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() {
    //
  },
  Php: function() {
    //
  },
  JavaScript: function() {
    //
  }
}

使用时只需要定义好数据

var data = [
  { type: 'Java', content: 'Java后端最好用的语言' },
  { type: 'Php', content: '世界上最好的语言' },
  { type: 'JavaScript', content: '前端语言' },
]
for (var i = 2; i >= 0; i--) {
  Factory(data[i].type, data[i].content)
}

3、抽象工厂模式

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

//抽象工厂模式
var VehicleFactory = function(subType, superType) {
  //判断抽象工厂中时候有该抽象类
  if (typeof VehicleFactory[superType] === 'function') {
    //缓存类
    function F() {}
    //继承父类属性和方法
    F.prototype = new VehicleFactory[superType]()
    //将子类的constructor指向子类
    subType.constructor = subType
    //子类原型继承父类
    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('抽象方法不能调用')
  },
  getSpeed: function() {
    return new Error('抽象方法不能调用')
  }
}
//货车抽象类
VehicleFactory.Truck = function(){
  this.type = 'truck'
}
VehicleFactory.Truck.prototype = {
  getPrice:function(){
    return new Error('抽象方法不能调用')
  },
  getSpeed:function(){
    return new Error('抽象方法不能调用')
  }
}

使用如下,通过抽象工厂函数,我们能够知道每一个子类属于哪一个类别,同时他们也具备了该类别所必备的属性和方法。由于js不支持抽象化创建和虚拟方法。所以这种模式使用不广泛。

var BMW = function(price,speed){
  this.price = price
  this.speed = speed
}
VehicleFactory(BMW,'Car')
BMW.prototype.getPrice = function(){
  return this.price
}
BMW.prototype.getSpeed = function(){
  return this.speed
}
console.log(new BMW('bmw',100))

5、参考资料

《JavaScript设计模式 张容铭》

《JavaScript设计模式 》Addy Osmani著 徐涛译版

6、结束语

最近在看有关js设计模式的知识,整理出来作为笔记,如果错误,欢迎大家指正,谢谢🙏