一、定义
工厂模式是一种用来创建对象的设计模式
二、核心
我们不暴露对象创建的逻辑,而是将逻辑封装在一个函数内,那么这个函数可以成为工厂。
工厂模式根据抽象程度的不同可以分为:1.简单工厂 2.工厂方法 3.抽象工厂
三、实现
-
简单工厂模式
例如有一家桌子点,出售各种桌子
// ============ 简单工厂 =============
/** 桌子抽象类 */
class Desk {
getType () {
return ''
}
}
/** 塑料桌 */
class PlasticDesk extends Desk {
getType() {
return '塑料桌'
}
}
/** 木头桌 */
class WoodDesk extends Desk {
getType() {
return '木头桌'
}
}
/** (桌子)工厂 */
class DeskFactory {
static createDesk (type) {
switch (type) {
case '塑料':
return new PlasticDesk();
case '木头':
return new WoodDesk;
default:
return null;
}
}
}
// 测试使用
const desk = DeskFactory.createDesk('木头')
console.log(desk.getType()) // => 木头桌
优缺点:
只需要传递一个合法的参数,就可以获取到你想要的对象,而无需知道创建的具体的细节。但是在函数内包含了所有对象的构造函数和判断逻辑的代码, 每次如果需要添加一个对象,那么我们需要新增一个构造函数,当我们需要维护的对象不是上面这2个,而是20个或者更多,那么这个函数将会成为超级函数,使得我们难以维护。所以简单工厂模式只适用于在创建时对象数量少,以及逻辑简单的情况。
-
工厂方法模式
对于创建多类对象,简单工厂就不太实用了。
通过工厂方法模式可以轻松的创建多个类的实例对象,而且创建对象的方式避免了使用者与对象类之间的耦合,用户不必关心创建该对象的具体类,只需调用工厂方法即可。
工厂方法模式本意是将实际创造的对象推迟到子类中,这样核心类就变成了抽象类。但是在js中很难像那些传统面向对象语言那样去实现抽象类,所以在js中我们只需要参考他的思想即可。
// ============ 工厂方法 =============
const Factory = function (type, content) {
if (this instanceof Factory) {
new this[type](content);
} else {
return new Factory(type, content);
}
}
//工厂原型中设置创建所有类型数据对象的基类
Factory.prototype = {
Wood: function(content){
console.log(content);
},
Plastic: function(content){
console.log(content);
}
}
// 测试
const a = Factory('Wood', '木头桌')
const b = Factory('Plastic', '塑料桌')
console.log(a === b)
// 输出:
木头桌
塑料桌
false
工厂方法模式面对的目标一般都是单类的,就比如工厂方法中所举的例子,目标就是桌子这一类商品。
如果是这样的呢:生产的是桌椅组合,目标的一套商品,每一套商品中的每类商品的种类的不同的,不同的组合形成不同的套装。这种情况下,就需要使用抽象工厂模式。
-
抽象工厂模式
// ============ 抽象工厂 =============
// 定义家具工厂抽象类
class FurnitureFactory {
crateDesk () {}
createChair () {}
}
/** (木料)工厂 */
class WoodFactory extends FurnitureFactory {
crateDesk () {
return new WoodDesk();
}
createChair () {
return new WoodChair();
}
}
/** 木桌 */
class WoodDesk {
constructor () {
console.log('木头桌子')
}
}
/** 木椅 */
class WoodChair {
constructor () {
console.log('木头椅子')
}
}
/** (塑料)工厂 */
class PlasticFactory extends FurnitureFactory{
crateDesk () {
return new PlasticDesk();
}
createChair () {
return new PlasticChair();
}
}
/** 塑料桌 */
class PlasticDesk {
constructor () {
console.log('塑料桌子')
}
}
/** 塑料椅 */
class PlasticChair {
constructor () {
console.log('塑料椅子')
}
}
// 测试
const factory = new WoodFactory();
factory.crateDesk()
const factory2 = new PlasticFactory();
factory2.createChair();
输出:
木头桌子
塑料椅子
不过抽象工厂的问题也是显而易见的,比如我们要加个凳子,就需要修改所有的工厂,给所有的工厂都加上制造凳子的方法。这有点违反了对修改关闭,对扩展开放这个设计原则。