工厂模式
定义
工厂模式可以将对象的创建过程封装在工厂类中,使得消费者(使用者)和生产者(实现者)解耦。通过工厂模式,消费者不需要直接使用 new 关键字来创建对象,而是通过调用工厂类的方法来获取所需的对象。 就是根据不同的输入返回不同的实例,一般用来创建同一类对象,它的主要思想就是将对象的创建与对象的实现分离。

在工厂模式中,工厂充当了一个生产标准规格商品的地方。它接收参数(原料),根据`参数的不同选择实例化合适的对象(特定规格的产品),并将其返回给使用者。
这样做的好处之一是解耦。使用工厂模式,使用者无需直接依赖具体的对象实现,而只需通过工厂来获取所需的对象。这样,当需要更换或扩展对象实现时,使用者的代码不需要做出太多改动,只需要修改工厂的实现即可。
另外,通过工厂模式可以实现面向抽象编程。工厂模式中的抽象产品定义了产品的接口或抽象类,使用者只需要操作抽象产品,而无需关心具体产品的细节。这样可以提高代码的灵活性和可维护性,也方便进行类型检查和静态分析。
在创建对象时,不暴露具体的逻辑,而是将逻辑封装在函数中,那么这个函数就可以被视为一个工厂。工厂模式根据抽象程度的不同可以分为:简单工厂、工厂方法、抽象工厂。
一个简单的例子,我们去餐馆吃饭,只需要按照菜单上的菜名进行点餐,然后菜做出来之后,不需要知道这些菜是怎么做的,只管吃就好了。在这里面,餐馆就相当于工厂,负责生产菜品,访问者通过餐馆就可以拿到产品。
使用场景
- 对象的创建比较复杂,而访问者无需知道创建的具体流程;
- 处理大量具有相同属性的小对象;
优缺点
优点
- 封装性好:工厂模式可以将对象的创建和使用分离,客户端只需要知道使用工厂方法来创建对象即可,无需了解具体的创建细节。
- 扩展性强:通过工厂模式,可以方便地添加新的产品类并创建对应的工厂类,而不影响已有的代码结构和客户端使用。
- 符合开放封闭原则:新增产品类不需修改原有代码,只需新增对应的产品类和工厂类,符合软件设计原则。
缺点
- 增加复杂度:引入工厂模式会增加代码的复杂度和结构,可能需要新增很多工厂类,增加了代码量。
- 不适用于简单对象的创建:工厂模式适合创建复杂对象的场景,如果只需要创建简单对象,使用工厂模式可能过于繁琐。
- 需要预先知道具体产品类:工厂模式需要事先了解可能会创建的产品类,而且随着产品种类的增加,工厂类也会增多。
实现
特点 | 简单工厂 | 工厂方法 | 抽象工厂 |
---|---|---|---|
定义 | 一个工厂类负责所有产品的实例化 | 定义了一个接口用于创建对象,让子类决定实例化哪一个类 | 提供一个创建一系列相关或相互依赖对象的接口 |
实现简单 | 创建对象的逻辑集中在单个工厂类中 | 创建对象的逻辑分布在不同的工厂类中 | 创建对象的逻辑分散在不同的工厂接口中 |
扩展性 | 随着产品种类的增加,工厂类会变得庞大且不易维护 | 可以通过增加新的工厂类来扩展新产品的生产 | 可以随意增加产品谢列或者产品族 |
类型 | 一对一关系 | 一对多关系 | 多对多关系 |
示例 | 简单实例化对象 | 通过工厂基类和具体子类实例化对象 | 通过抽象工厂接口和具体工厂类实例化对象 |
生产实例(商品)的工厂可以是小作坊,只生产少量简单的商品,也可以是大型的复杂工厂,因此基于场景复杂程度又有多个工厂模式:
类别 | 说明 |
---|---|
简单工厂(Simple Factory) | 小作坊,适用于少量对象的创建,集中式管理,使用简单、扩展不便 |
工厂方法(Factory Method) | 正规小工厂,每种产品一个独立工厂,偏平化扩展 |
抽象工厂(Abstract Factory) | 集团化大厂,产品种类、层级众多,需要多层级的工厂来管理,代码也稍复杂 |
简单工厂
简单工厂模式又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象类的实例。主要用来创建同一类对象。
class User {
constructor(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
static getInstance(role) {
switch (role) {
case 'superAdmin':
return new User({ name: '超级管理员', viewPage: ['首页', '应用数据', '权限管理'] });
case 'admin':
return new User({ name: '管理员', viewPage: ['首页', '应用数据'] });
case 'user':
return new User({ name: '普通用户', viewPage: ['首页'] });
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
}
let superAdmin = User.getInstance('superAdmin');
console.log(superAdmin); // 输出: User { name: "超级管理员", viewPage: ["首页", "应用数据", "权限管理"] }
let admin = User.getInstance('admin');
console.log(admin); // 输出: User { name: "管理员", viewPage: ["首页", "应用数据"] }
let normalUser = User.getInstance('user');
console.log(normalUser); // 输出: User { name: "普通用户", viewPage: ["首页"] }
简单工厂模式的优势就在于,只需要一个参数,就可以获得所需的对象,无需知道对象创建的具体细节。但是,在函数内部包含了对象所有的创建逻辑,和判断逻辑的代码,如果判断逻辑很多,或者代码逻辑很复杂,这样工厂函数就会变的很复杂,很庞大,难以维护。所以,简单工厂只适合以下情况:
- 创建的对象数量较少;
- 创建的对象的逻辑不是很复杂。
工厂方法
工厂方法模式定义了一个用于创建对象的工厂方法,由子类决定具体创建哪个类的对象。工厂方法模式将对象的创建延迟到子类中,客户端只需要依赖抽象的工厂接口,而不需要关心具体的产品类。
class User {
constructor(name = '', viewPage = []) {
if (new.target === User) {
throw new Error('抽象类不能实例化!')
}
this.name = name
this.viewPage = viewPage
}
}
class UserFactory extends User {
constructor(name, viewPage) {
super(name, viewPage)
}
create(role) {
switch (role) {
case 'superAdmin':
return new UserFactory('超级管理员', [
'首页',
'应用数据',
'权限管理',
])
break
case 'admin':
return new UserFactory('管理员', ['首页', '应用数据'])
break
case 'user':
return new UserFactory('普通用户', ['首页'])
break
default:
throw new Error('参数错误, 可选参数:superAdmin、admin、user')
}
}
}
let userFactory = new UserFactory()
let superAdmin = userFactory.create('superAdmin')
let admin = userFactory.create('admin')
let user = userFactory.create('user')
console.log(superAdmin)
console.log(admin)
console.log(user)
抽象工厂模式
抽象工厂模式通过提供一个接口来创建一系列相关的产品,这些产品通常属于不同的类,但又有着某种关联或者依赖关系。通过使用抽象工厂模式,我们可以确保创建的产品是相互配合使用的,并且隐藏了具体产品的实现细节。
在抽象工厂模式中,有两个核心概念:抽象工厂和具体工厂。抽象工厂定义了一组用于创建产品的抽象方法,而具体工厂则实现了这些抽象方法,并负责创建具体的产品。
具体工厂类根据不同的需求实现了抽象工厂中定义的方法,每个方法都会返回一个具体的产品对象。这些产品对象通常属于同一个产品簇,它们具有相似的特性或者功能。
通过使用抽象工厂模式,我们可以在不修改客户端代码的情况下,更换具体工厂类,从而创建不同簇的产品。这种灵活性使得我们可以根据需要动态地改变所使用的产品。
在网站登录中,会使用不同的第三方登录方式,例如微信、QQ、微博,这三类账号就是对应的类簇。在抽象工厂中,类簇一般用于父类的定义,并在父类中定义一些抽象的方法(声明但不能使用的方法),在通过抽象工厂让子类继承父类,所以,抽象工厂实际上就是实现子类继承父类的方法。
// 抽象工厂接口
class AuthFactory {
createLogin() {}
}
// 具体工厂类 - 微信登录
class WeChatAuthFactory extends AuthFactory {
createLogin() {
return new WeChatLogin();
}
}
// 具体工厂类 - QQ登录
class QQAuthFactory extends AuthFactory {
createLogin() {
return new QQLogin();
}
}
// 具体工厂类 - 微博登录
class WeiboAuthFactory extends AuthFactory {
createLogin() {
return new WeiboLogin();
}
}
// 抽象登录类
class AbstractLogin {
authenticate() {}
}
// 具体登录类 - 微信登录
class WeChatLogin extends AbstractLogin {
authenticate() {
console.log('WeChat login');
}
}
// 具体登录类 - QQ登录
class QQLogin extends AbstractLogin {
authenticate() {
console.log('QQ login');
}
}
// 具体登录类 - 微博登录
class WeiboLogin extends AbstractLogin {
authenticate() {
console.log('Weibo login');
}
}
// 使用示例
function performAuthentication(factory) {
const login = factory.createLogin();
login.authenticate();
}
const weChatFactory = new WeChatAuthFactory();
performAuthentication(weChatFactory);
const qqFactory = new QQAuthFactory();
performAuthentication(qqFactory);
const weiboFactory = new WeiboAuthFactory();
performAuthentication(weiboFactory);