JavaScript设计模式:工厂模式

ES6设计模式解析
本文深入探讨了ES6视角下的设计模式,通过具体实例讲解了简单工厂、工厂方法及抽象工厂模式的应用,揭示了设计模式背后的逻辑思维。

强烈推荐大神写的文章:从ES6重新认识设计模式,从ES5、ES6的角度剖析了设计模式,还给出了应用实例。此篇文章就不介绍ES6的写法了,重点在于设计模式的思想。

简单工厂

简单工厂模式,又称为静态工厂方法,可以这样子来理解,工厂就是售货员,我们要买什么东西只需要告诉售货员,让他来拿给你,我们不需要去关注这个东西摆放在哪里,或者价格如何。

具体的实现分为两种:

  • 通过类实例化对象创建
//简单工厂
let UserFactory = function (role) {
  function SuperAdmin() {
    this.name = "超级管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
  }
  function Admin() {
    this.name = "管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
  }
  function NormalUser() {
    this.name = '普通用户',
    this.viewPage = ['首页', '通讯录', '发现页']
  }

  switch (role) {
    case 'superAdmin':
      return new SuperAdmin();
      break;
    case 'admin':
      return new Admin();
      break;
    case 'user':
      return new NormalUser();
      break;
    default:
      throw new Error('参数错误, 可选参数:superAdmin、admin、user');
  }
}

//调用
let superAdmin = UserFactory('superAdmin');
let admin = UserFactory('admin') 
let normalUser = UserFactory('user')

UserFactory就是一个简单工厂,在该函数中有3个构造函数分别对应不同的权限的用户。当我们调用工厂函数时,只需要传递superAdmin, admin, user这三个可选参数中的一个获取对应的实例对象

  • 通过一个新对象然后包装增强其属性和功能
function createBook(name,time,type){
    var o = new Object();
    o.name = name;
    o.time = time;
    o.type = type;
    o.getName = function(){
        console.log(this.name);
    };
    return o;
}

var book = createBook("js book",2014,"js");

book.getName();

有点像是寄生式继承

工厂方法模式

由于每次有新的需求增加,都需要去修改工厂和添加相关的类,难以维护,简单工厂只能作用于创建的对象数量较少,对象的创建逻辑不复杂时使用

我们来看看安全工厂方法

//安全模式创建的工厂方法函数
let UserFactory = function(role) {
  if(this instanceof UserFactory) {
    var s = new this[role]();
    return s;
  } else {
    return new UserFactory(role);
  }
}

//工厂方法函数的原型中设置所有对象的构造函数
UserFactory.prototype = {
  SuperAdmin: function() {
    this.name = "超级管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
  },
  Admin: function() {
    this.name = "管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
  },
  NormalUser: function() {
    this.name = '普通用户',
    this.viewPage = ['首页', '通讯录', '发现页']
  }
}

//调用
let superAdmin = UserFactory('SuperAdmin');
let admin = UserFactory('Admin') 
let normalUser = UserFactory('NormalUser')

所谓的安全模式类,就是说如果有人不知道这个对象是一个类,那么在使用的时候可能会忽略new关键字而直接去执行这个类。为了避免这种情况,我们在构造函数开始时先判断this指代是不是类,如果不是的话,当然是指向window,就要帮他创建对象并返回。

工厂方法模式:将实际创建对象工作推迟到子类当中。这样有新需求的时候,只需要在工厂类的原型里面做修改就可以了。

抽象工厂

JavaScript的abstract是一个保留字,并没有提供抽象类,抽象类是一种声明但不能使用的类,当你使用的时候就会报错。ES6也没有实现abstract,但是我们可以使用new.target来模拟出抽象类,而在ES5中,我们可以在类的方法中手动地抛出错误来模拟抽象类。

let WechatUser = function() {}
WechatUser.prototype = {
  getName: function() {
    return new Error('抽象方法不能调用');
  }
}

在抽象工厂中,类簇一般用父类定义,并在父类中定义一些抽象方法,再通过抽象工厂让子类继承父类。所以,抽象工厂是用来创建子类的,是实现子类继承父类的方法。下面是ES5的写法。

let AccountAbstractFactory = function(subType, superType) {
  //判断抽象工厂中是否有该抽象类
  if(typeof AccountAbstractFactory[superType] === 'function') {
    //缓存类
    function F() {};
    //继承父类属性和方法
    F.prototype = new AccountAbstractFactory[superType] ();
    //将子类的constructor指向子类
    subType.constructor = subType;
    //子类原型继承父类
    subType.prototype = new F();

  } else {
    throw new Error('抽象类不存在!')
  }
}

//微信用户抽象类
AccountAbstractFactory.WechatUser = function() {
  this.type = 'wechat';
}
AccountAbstractFactory.WechatUser.prototype = {
  getName: function() {
    return new Error('抽象方法不能调用');
  }
}

//qq用户抽象类
AccountAbstractFactory.QqUser = function() {
  this.type = 'qq';
}
AccountAbstractFactory.QqUser.prototype = {
  getName: function() {
    return new Error('抽象方法不能调用');
  }
}

//新浪微博用户抽象类
AccountAbstractFactory.WeiboUser = function() {
  this.type = 'weibo';
}
AccountAbstractFactory.WeiboUser.prototype = {
  getName: function() {
    return new Error('抽象方法不能调用');
  }
}

实例化的做法是:定义子类,然后让子类继承相应的产品簇抽象类。这里就不贴代码了。

抽象工厂是唯一一种抽象化创建模式,区别于简单工厂创建单一对象,工厂方法创建多类对象。

目前ES6的与语法糖class和extend已经带给我们很多方便,但由于JavaScript中不支持抽象化创建和虚拟方法,抽象工厂模式也就难以广泛应用,而且工厂模式本身是用于大型工程项目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值