第三章 设计模式 - 创建型 - 工厂模式

发布时间 2023-03-28 15:47:14作者: caix-1987

工厂模式的概念

1、工厂模式 是用来创建对象的一种 最常用的 设计模式

2、不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂

3、工厂模式根据抽象程度的不同可以分为 3 类

   1、简单工厂  【 静态工厂 】
   
   2、工厂方法
   
   3、抽象工厂

工厂模式的功能

1、解耦,通过使用工程方法而不是 new 关键字;

2、将所有实例化的代码集中在一个位置减少代码重复,降低出错;

3、工厂模式最重要的优点是:可以在父类实现一些相同的方法,而具体要实现的业务逻辑可以放在子类中,通过子类重写父类的方法,去实现自己的业务逻辑。

4、工厂模式弱化对象间的耦合,父类专注于实现重复性的功能,子类专注于具体的业务逻辑,这样可以减少冗余代码。

工厂模式的实现

1、简单工厂

简单工厂模式又叫静态工厂方法,用来创建某一种产品对象的实例,用来创建单一对象。

class Factory {
  constructor (username, pwd, role) {
  	this.username = username;
    this.pwd = pwd;
    this.role = role;
  }
}

class CreateRoleFactory {
	static create (username, pwd, role) {
  	return new Factory(username, pwd, role);
  }
}

const admin = CreateRoleFactory.create('张三', '222', 'admin');
2、工厂方法

在实际工作中,各用户角色所具备的能力是不同的,因此简单工厂是无法满足的,这时候就可以考虑使用工厂方法来代替。

工厂方法的本意是将实际创建对象的工作推迟到子类中。

class User {
	constructor (name, menuAuth) {
  	if (new.target === User) throw new Error('User 不能被实例化');
    this.name = name;
    this.menuAuth = menuAuth;
  }
}

class UserFactory extends User {
	constructor (...props) {
  	super(...props);
  }
  static create (role) {
  	const roleCollection = new Map([
    	['admin', () => new UserFactory('管理员', ['首页', '个人中心'])],
      ['user', () => new UserFactory('普通用户', ['首页'])]
    ])
    
    return roleCollection.get(role)();
  }
}

const admin = UserFactory.create('admin');
console.log(admin); // {name: "管理员", menuAuth: Array(2)}
const user = UserFactory.create('user');
console.log(user); // {name: "普通用户", menuAuth: Array(1)}
3、抽象工厂

随着业务形态的变化,一个用户可能在多个平台上同时存在,显然工厂方法也不再满足了,这时候就要用到抽象工厂。

抽象工厂模式 是对类的工厂抽象用来创建产品类簇,不负责创建某一类产品的实例。

class User {
  constructor (hospital) {
    if (new.target === User) throw new Error('抽象类不能实例化!');
    this.hospital = hospital;
  }
}
// 浙一
class ZheYiUser extends User {
  constructor(name, departmentsAuth) {
    super('zheyi_hospital');
    this.name = name;
    this.departmentsAuth = departmentsAuth;
  }
}
// 萧山医院
class XiaoShanUser extends User {
  constructor(name, departmentsAuth) {
    super('xiaoshan_hospital');
    this.name = name;
    this.departmentsAuth = departmentsAuth;
  }
}

const getAbstractUserFactory = (hospital) => {
  switch (hospital) {
    case 'zheyi_hospital':
      return ZheYiUser;
      break;
    case 'xiaoshan_hospital':
      return XiaoShanUser;
      break;
  }
}

const ZheYiUserClass = getAbstractUserFactory('zheyi_hospital');
const XiaoShanUserClass = getAbstractUserFactory('xiaoshan_hospital');

const user1 = new ZheYiUserClass('王医生', ['外科', '骨科', '神经外科']);
console.log(user1);
const user2 = newXiaoShanUserClass('王医生', ['外科', '骨科']);
console.log(user2);

工厂模式的场景及小结其一

简单工厂模式又叫静态工厂方法,用来创建某一种产品对象的实例,用来创建单一对象;

工厂方法模式是将创建实例推迟到子类中进行;

抽象工厂模式是对类的工厂抽象用来创建产品类簇,不负责创建某一类产品的实例。

在实际的业务中,需要根据实际的业务复杂度来选择合适的模式。对于非大型的前端应用来说,灵活使用简单工厂其实就能解决大部分问题。

小结:

  外部不许关心内部构造器是怎么生成的,只需调用一个 工厂方法 生成一个实例即可;
  
  构造函数和创建对象分离,符合开放封闭原则。

使用场景: 比如根据权限生成不同用户。

工厂模式的场景及小结其二

适用场景

  1、如果你不想让某个子系统与较大的那个对象之间形成强耦合,而是想运行时从许多子系统中进行挑选的话,那么工厂模式是一个理想的选择
  
  2、将 new 操作 简单封装,遇到 new 的时候就应该考虑是否用工厂模式;
  
  3、需要依赖具体环境创建不同实例,这些实例都有相同的行为,这时候我们可以使用工厂模式,简化实现的过程,同时也可以减少每种对象所需的代码量,有利于消除对象间的耦合,提供更大的灵活性

优点

  1、创建对象的过程可能很复杂,但我们只需要关心创建结果。
  
  2、构造函数和创建者分离, 符合 “开闭原则”
  
  3、一个调用者想创建一个对象,只要知道其名称就可以了。
  
  4、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。

缺点

  1、添加新产品时,需要编写新的具体产品类,一定程度上增加了系统的复杂度
  
  2、考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度

什么时候不用

  1、当被应用到错误的问题类型上时,这一模式会给应用程序引入大量不必要的复杂性,除非为创建对象提供一个接口是我们编写的库或者框架的一个设计上目标,否则我会建议使用明确的构造器,以避免不必要的开销。
  
  2、由于对象的创建过程被高效的抽象在一个接口后面的事实,这也会给依赖于这个过程可能会有多复杂的 单元测试 带来问题。