设计模式专题之工厂模式(六)
Opened this issue · 0 comments
工厂模式(Factory Pattern)
定义:创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
简单的说
- 将 new 操作单独封装,只对外提供相应接口
- 遇到new 时,就要考虑是否应该使用工厂模式
工厂模式有三种形式:简单工厂模式(Simple Factory)、工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory)。在 javascript 中我们最常见的当属简单工厂模式。
作用
- 主要用于隐藏创建实例的复杂度,只需对外提供一个接口
- 实现构造函数和创建者的分离,满足开放封闭的原则
实例
// 定义产品
class Product {
constructor(name) {
this.name = name
}
init() {
console.log('初始化产品')
}
}
// 定义工厂
class Factory {
create(name) {
return new Product(name) // 重点!!!
}
}
let c = new Factory()
let p = c.create('p1')
p.init()
工厂模式最直观的地方在于,创建产品对象不是通过直接new 产品类实现,而是通过工厂方法实现。现在再用一个稍微有些好看的例子描述一下简单工厂:
//User类
class User {
constructor(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
static getInstance(role) {
switch (role) {
case 'superAdmin':
return new User({ name: '超级管理员', viewPage: ['首页', '通讯录', '发现页', '应用数据', '权限管理'] });
break;
case 'admin':
return new User({ name: '管理员', viewPage: ['首页', '通讯录'] });
break;
default:
throw new Error('params error')
}
}
}
//调用
let superAdmin = user.getInstance('superAdmin');
let admin = user.getInstance('admin');
通过上例,我们可以看到,每次创建新的对象实例时,只需要传入相应的参数,就可以得到指定的对象实例。最直观的例子是如果不用工厂模式,那代码中是不是就会多出好多个new,这样看着也不太舒服。
其实简单工厂模式已经能满足我们前端大部分业务场景了,如果非要说其一个缺陷,那就是每次有新实例时,我们需要重写这个User大类,总归感觉和后面所述的装饰器模式有一些冲突。此时,工厂方法模式就出来了,其核心**就是独立出一个大的User类,将创建实例对象的过程用其子类来实现:
class User {
constructor(name = '', viewPage = []) {
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;
default:
throw new Error('params error');
}
}
}
let userFactory = new UserFactory();
let superAdmin = userFactory.create('superAdmin');
let admin = userFactory.create('admin');
let user = userFactory.create('user');
这样,虽然也得通过 new 一个实例,但至少我们可以无需修改User类里面的东西,虽说代码量上感觉和简单模式差不了多少,但**主体确实就是这样。
应用场景
jQuery选择器
$('div')
和 new $('div')
有何区别? 为什么 $('div')
就能直接实现 new
的效果,同时去除了 new $('div')
这种$('div')
去除了 new
书写繁杂的弊端,还能实现完美的链式操作代码简介,就是因为$
内置的实现机制是工厂模式。其底层代码如下:
class jQuery {
constructor(selector) {
super(selector)
}
// ...
}
window.$ = function(selector) {
return new jQuery(selector)
}
Vue 异步组件
Vue.component('async-example' , (resolve , reject) => {
setTimeout(function() {
resolve({
template: `<div>I am async!</div>`
})
}, 1000)
})
除了上述两个常见的实例场景,还有React.createElement()
也是工厂原理。所以,当我们平时遇到要创建实例的时候,就可以想想能否用工厂模式实现了。