解答问题前,了解什么是工厂模式我以为更重要些。 工厂模式其实也称建立模式,是用于建立对象的一种方式。能够说就是用来代替 new 实例化对象,决定了实例化哪个类,从而解决解耦问题。javascript
举个例子:html
一个工厂接到一笔订单(传参),而后根据这个订单类型(参数)来安排产品线(实例化哪一个类),固然客户能够要求一些产品的工艺属性(抽象工厂)。这其中厂长(工厂模式)只负责调度,即安排产品零件流水线。你应该知道的是,工厂有个特色就是产出体量大、类似度高的产品。若是你要作单必定制化的产品,那这笔订单给工厂就不适用了。java
new
关键字;不暴露建立对象的具体逻辑,而是将将逻辑封装在一个函数中,那么这个函数就能够被视为一个工厂。node
也能够叫静态工厂模式,用一个工厂对象建立同一类对象类的实例。现实生活中,用户在平台仍是分等级的,角色不一样,权限也不一样。jquery
1.ES5 实现git
// 0.0.2/es5.simple.factory.js
function Role(options){
this.role = options.role;
this.permissions = options.permissions;
}
Role.prototype.show = function (){
var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', ');
console.log(str)
}
function simpleFactory(role){
switch(role) {
case 'admin':
return new Role({
role: '管理员',
permissions: ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论']
});
break;
case 'developer':
return new Role({
role: '开发者',
permissions: ['开发', '推送', '提问', '评论']
});
break;
default:
throw new Error('参数只能为 admin 或 developer');
}
}
// 实例
const xm = simpleFactory('admin');
xm.show();
const xh = simpleFactory('developer');
xh.show();
const xl = simpleFactory('guest');
xl.show();
复制代码
2.ES6 实现github
// 0.0.2/simple.factory.js
class SimpleFactory {
constructor(opt) {
this.role = opt.role;
this.permissions = opt.permissions;
}
// 静态方法
static create(role) {
switch (role) {
case 'admin':
return new SimpleFactory({
role: '管理员',
permissions: ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论']
});
break;
case 'developer':
return new SimpleFactory({
role: '开发者',
permissions: ['开发', '推送', '提问', '评论']
});
break;
default:
throw new Error('参数只能为 admin 或 developer');
}
}
show() {
const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`;
console.log(str);
}
}
// 实例
const xm = SampleFactory.create('admin');
xm.show();
const xh = SampleFactory.create('developer');
xh.show();
const xl = SampleFactory.create('guest');
xl.show();
复制代码
或编程
// 0.0.2/simple.factory1.js
class Role {
constructor(options) {
this.role = options.role;
this.permissions = options.permissions;
}
show() {
const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`;
console.log(str);
}
}
class SimpleFactory {
constructor(role) {
this.role = role;
}
// 静态方法
static create(role) {
switch (role) {
case 'admin':
return new Role({
role: '管理员',
permissions: ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论']
});
break;
case 'developer':
return new Role({
role: '开发者',
permissions: ['开发', '推送', '提问', '评论']
});
break;
default:
throw new Error('参数只能为 admin 或 developer');
}
}
}
// 实例
const xm = SimpleFactory.create('admin');
xm.show();
const xh = SimpleFactory.create('developer');
xh.show();
const xl = SimpleFactory.create('guest');
xl.show();
复制代码
或设计模式
// 0.0.2/simple.factory2.js
class Role {
constructor(options) {
this.role = options.role;
this.permissions = options.permissions;
}
show() {
const str = `是一个${this.role}, 权限:${this.permissions.join(', ')}`;
console.log(str);
}
}
class SimpleFactory {
constructor(role) {
if(typeof this[role] !== 'function') {
throw new Error('参数只能为 admin 或 developer');
}
return this[role]();
}
admin() {
return new Role({
role: '管理员',
permissions: ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论']
});
}
developer() {
return new Role({
role: '开发者',
permissions: ['开发', '推送', '提问', '评论']
});
}
}
// 实例
const xm = new SimpleFactory('admin');
xm.show();
const xh = new SimpleFactory('developer');
xh.show();
const xl = new SimpleFactory('guest');
xl.show();
复制代码
上例中,simpleFactory
就是一个简单工厂,2个实例对应不一样的权限,调用工厂函数时,只需传递 admin
或 developer
就可获取对应的实例对象。缓存
1.简单工厂函数适用场景
2.简单工厂函数不适用场景
create
内包含了全部建立对象(构造函数)的判断逻辑代码,若是要增长新的构造函数还须要修改函数 create
(判断逻辑代码),当可选参数 role
变得更多时,那函数 create
的判断逻辑代码就变得臃肿起来,难以维护。将实际建立对象工做推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只须要将子类注册进工厂方法的原型对象中便可。
1.安全模式类,能够屏蔽使用类的错误形成的错误
// 0.0.2/secure.function.factory.js
function Factory(){
if(!(this instanceof Factory)) {
return new Factory();
}
}
Factory.prototype.show = function(){
console.log('factory show');
}
var f = new Factory();
f.show();
复制代码
2.ES5 实现,ES5 没有像传统建立类的方式那样建立抽象类,因此工厂方法模式只需参考其核心思想便可。可将工厂方法看作一个实例化对象工厂类(采用安全模式类),将建立对象的基类放在工厂方法类的原型中便可。当须要添加新类时,只需挂载在 FunctionFactory.prototype
上,无需修改工厂方法,也实现了 OCP 原则。
// 0.0.2/es5.function.factory.js
function FunctionFactory(role) {
if(!(['admin', 'developer'].indexOf(role) > -1)){
throw new Error('参数只能为 admin 或 developer');
}
// 安全的工厂方法
if (this instanceof FunctionFactory) {
return this[role]();
}
return new FunctionFactory(role);
}
FunctionFactory.prototype.show = function () {
var str = '是一个' + this.role + ', 权限:' + this.permissions.join(', ');
console.log(str)
}
FunctionFactory.prototype.admin = function (permissions) {
this.role = '管理员';
this.permissions = ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论'];
}
FunctionFactory.prototype.developer = function (permissions) {
this.role = '开发者';
this.permissions = ['开发', '推送', '提问', '评论'];
}
var xm = FunctionFactory('admin');
xm.show();
var xh = new FunctionFactory('developer');
xh.show();
var xl = new FunctionFactory('guest');
xl.show();
复制代码
3.ES6 实现,因为 ES6 中尚未 abstract
,就用 new.target
来模拟出抽象类(new.target
指向被 new
执行的构造函数),判断 new.target
是否指向了抽象类,若是是就报错。
// 0.0.2/function.factory.js
class FunctionFactoryBase { // 抽象类
constructor(role) {
if (new.target === FunctionFactoryBase) {
throw new Error('抽象类不能实例');
}
this.role = role;
}
}
class FunctionFactory extends FunctionFactoryBase { // 子类
constructor(role) {
super(role);
}
static create(role) {
switch (role) {
case 'admin':
return new FunctionFactory({
role: '管理员',
permissions: ['设置', '删除', '新增', '建立', '开发', '推送', '提问', '评论']
});
break;
case 'developer':
return new FunctionFactory({
role: '开发者',
permissions: ['开发', '推送', '提问', '评论']
});
break;
default:
throw new Error('参数只能为 admin 或 developer');
}
}
show() {
const { role, permissions } = this.role;
const str = `是一个${role}, 权限:${permissions.join(', ')}`;
console.log(str)
}
}
// let xl = new FunctionFactoryBase(); // 此行会报错,注释后方可正常执行后面
let xm = FunctionFactory.create('admin');
xm.show()
let xh = FunctionFactory.create('developer');
xh.show()
let xl = FunctionFactory.create('guest');
xl.show()
复制代码
抽象工厂只留对外的口子,不作事,留给外界覆盖(子类重写接口方法以便建立的时候指定本身的对象类型)。主要用于对产品类簇的建立,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。
// 0.0.2/abstract.factory2.js
// 抽象工厂
function AbstractFactory(subType, superType) {
if (typeof AbstractFactory[superType] === 'function') {
//缓存类
function F() { }
//继承父类属性和方法
F.prototype = new AbstractFactory[superType]();
//将子类 constructor 指向子类(本身)
subType.prototype.constructor = subType;
//子类原型继承缓存类(父类)
subType.prototype = new F();
} else {
//不存在该抽象类抛出错误
throw new Error('抽象类不存在')
}
}
// 抽象类
AbstractFactory.Phone = function () {
this.type = 'Phone';
}
AbstractFactory.Phone.prototype = {
showType: function () {
return new Error('Phone 抽象方法 showType 不能调用');
},
showPrice: function () {
return new Error('Phone 抽象方法 showPrice 不能调用');
},
showColor: function () {
return new Error('Phone 抽象方法 showColor 不能调用');
}
}
AbstractFactory.Pad = function () {
this.type = 'Pad';
}
AbstractFactory.Pad.prototype = {
showType: function () {
return new Error('Pad 抽象方法 showType 不能调用');
},
showPrice: function () {
return new Error('Pad 抽象方法 showPrice 不能调用');
},
showColor: function () {
return new Error('Pad 抽象方法 showColor 不能调用');
}
}
// 抽象工厂实现对抽象类的继承
function Iphone(type, price, color) {
this.type = type;
this.price = price;
this.color = color;
}
//抽象工厂实现对 Phone 抽象类的继承
AbstractFactory(Iphone, 'Phone');
Iphone.prototype.showType = function () {
return this.type;
}
Iphone.prototype.showPrice = function () {
return this.price;
}
Iphone.prototype.showColor = function () {
return this.color;
}
function Ipad(type, price, color) {
this.type = type;
this.price = price;
this.color = color;
}
AbstractFactory(Ipad, 'Pad');
Ipad.prototype.showType = function () {
return this.type;
}
Ipad.prototype.showPrice = function () {
return this.price;
}
Ipad.prototype.showColor = function () {
return this.color;
}
// 实例
var iphone5s = new Iphone('iphone 5s', 3000, '白色');
console.log('今天刚买了' + iphone5s.showType() + ',价格是' + iphone5s.showPrice() + ',' + iphone5s.showColor())
var iphone8s = new Iphone('iphone 8s', 8000, '白色');
console.log('今天刚买了' + iphone8s.showType() + ',价格是' + iphone8s.showPrice() + ',' + iphone8s.showColor())
var ipad = new Ipad('ipad air', 2000, '骚红色');
console.log('今天刚买了' + ipad.showType() + ',价格是' + ipad.showPrice() + ',' + ipad.showColor())
复制代码
1.jQuery源码-工厂模式
// 0.0.2/jquery.factory.js
// 工厂模式
class jQuery {
constructor(selector) {
let slice = Array.prototype.slice;
let dom = slice.call(document.querySelectorAll(selector));
let len = dom ? dom.length : 0;
for (let i = 0; i < len; i++) {
this[i] = dom[i];
}
this.length = len
this.selector = selector || ''
}
addClass(name) {
console.log(name)
}
html(data) {
}
// 省略多个 API
}
// 工厂模式
window.$ = function(selector) {
return new jQuery(selector);
}
// 实例
const $li = $('li')
$li.addClass('item');
复制代码
2.React.createElement
实现
// jsx
var profile = (
<div> <img src='https://raw.githubusercontent.com/ruizhengyun/images/master/cover/ruizhengyun.cn_.png' className="profile" /> <h3>{[user.firstName, user.lastName].join(' ')}</h3> </div>
);
// 实现
var profile = React.createElement('div', null,
React.createElement('img', { src: 'https://raw.githubusercontent.com/ruizhengyun/images/master/cover/ruizhengyun.cn_.png', className: 'profile' }),
React.createElement('h3', null, [user.firstName, user.lastName].join(' '))
);
// 源码
class Vnode(tag, attrs, children) {
// ...
}
React.createElement = function(tag, attrs, children) {
return new Vnode(tag, attrs, children);
}
复制代码