一. 简单工厂模式
介绍
简单工厂模式的工厂类一般是使用静态方法,通过接收的参数的不同来返回不同的对象实例。
不修改代码的话,是无法扩展的,否则就违反了开放封闭原则。
示例
客户去购买咖啡,那么可以通过 CoffeFactory 来进行购买
/**
* 抽象咖啡类
*/
abstract class Coffee {
constructor(public name: string) { }
}
class LatteCoffee extends Coffee { }
class MachaCoffee extends Coffee { }
class AmericanoCoffee extends Coffee { }
// 简单工厂实现
class CoffeFactory {
static buy(name: string) {
switch (name) {
case 'LatteCoffee':
return new LatteCoffee('拿铁咖啡');
case 'MachaCoffee':
return new MachaCoffee('摩卡咖啡');
case 'AmericanoCoffee':
return new AmericanoCoffee('美式咖啡');
default:
throw new Error('没有您需要的咖啡')
}
}
}
console.log(CoffeFactory.buy('LatteCoffee'));
console.log(CoffeFactory.buy('MachaCoffee'));
console.log(CoffeFactory.buy('AmericanoCoffee'));
优点
客户端可以免除直接创建产品对象的责任,而仅仅是“消费”产品。简单工厂模式通过这种做法实现了对责任的分割
缺点
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则; 这种做法扩展性差,违背了开闭原则,也影响了可读性。 所以,这种方式使用在业务较简单,工厂类不会经常更改的情况。
前端应用场景
经典 jQuery 的创建就使用到了简单工厂;
具体源码地址 React 源码中的实现,判断每种类型的渲染区别以实现工厂模式;
二. 工厂方法模式
介绍
工厂方法模式 Factory Method , 又称多态性工厂模式;
在工厂方法模式中,核心的工厂类不在负责所有的产品的创建,而是将具体创建的工作交给工厂子类去做; 也就是说针对每一种产品提供一个工厂类,通过不同的工厂实例来创建不同的产品实例。 在同一等级结构中,支持增加任意产品。
示例
以上面的顾客点咖啡为例,用户只需要与咖啡店里的点餐员去进行接触点餐,然后对应的咖啡交给对应的人去制作对应的咖啡,也就是每个制作咖啡的人不是同一个人。
/**
* 抽象咖啡类
*/
abstract class Coffee {
constructor(public name: string) { }
}
class LatteCoffee extends Coffee { }
class MachaCoffee extends Coffee { }
class AmericanoCoffee extends Coffee { }
// 抽象咖啡工厂类
abstract class CoffeeFactory {
constructor() { }
}
class LatteCoffeeFactory extends CoffeeFactory {
createCoffe() {
console.log('您创建了一份拿铁咖啡');
}
}
class MachaCoffeeFactory extends CoffeeFactory {
createCoffe() {
console.log('您创建了一份摩卡咖啡');
}
}
class AmericanoCoffeeFactory extends CoffeeFactory {
createCoffe() {
console.log('您创建了一份美式咖啡');
}
}
// 在工厂方法里,不再由 Factory 来创建产品,而是先创建了具体的工厂,然后具体的工厂创建产品
class Factory {
static buy(name: string) {
switch (name) {
case 'LatteCoffee':
// 先创建了拿铁咖啡具体的工厂,然后再由具体的工厂再创建产品
return new LatteCoffeeFactory().createCoffe();
case 'MachaCoffee':
// 先创建了摩卡咖啡具体的工厂,然后再由具体的工厂再创建产品
return new MachaCoffeeFactory().createCoffe();
case 'AmericanoCoffee':
// 先创建了美式咖啡具体的工厂,然后再由具体的工厂再创建产品
return new AmericanoCoffeeFactory().createCoffe();
default:
throw new Error('没有您需要的咖啡')
}
}
}
console.log(Factory.buy('LatteCoffee'));
console.log(Factory.buy('MachaCoffee'));
console.log(Factory.buy('AmericanoCoffee'));
优点
允许系统在不修改具体工厂角色的情况下引进新产品
缺点
由于每加一个产品,就需要加一个产品工厂的类,使得系统中类的个数成倍增加,增加了代码的复杂度。
前端应用场景
React 源码体验 — createFactory
其余结合具体业务场景实现
三. 抽象工厂模式
介绍
抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象;
工厂方法模式针对的是同一类或同等级产品,而抽象工厂模式针对的是多种类的产品设计;
系统中有多个产品族,每个具体工厂负责创建同一族但属于不同产品登记(产品种类)的产品;
产品族是一组相关或相互依赖的对象; 系统一次只能消费某一族产品,即相同产品族的产品是一起被使用的;
当系统需要新增一个产品族时,只需要增加新的工厂类即可,无需修改源代码;
但是如果需要产品族中增加一个新种类的产品时,则所有的工厂类都需要修改。 抽象工厂是应对产品族概念的。比如说,每个汽车公司可能要同时生产轿车,货车,客车,那么每一个工厂都要有创建轿车,货车和客车的方法。 应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。
示例: 苹果公司的苹果笔记本、苹果手表、苹果手机等等; 华为公司的华为笔记本、华为手表、华为手机等等; 以上苹果/华为公司的产品,就可以称之为产品族。
/**
* 产品抽象类或接口
*/
abstract class MacProdoct { }
abstract class IWatchProdoct { }
abstract class PhoneProdoct { }
/**
* 具体产品实现类
*/
class AppleMacProdoct extends MacProdoct { }
class HuaweiMacProdoct extends MacProdoct { }
class AppleIWatchProdoct extends IWatchProdoct { }
class HuaweiIWatchProdoct extends IWatchProdoct { }
class ApplePhoneProdoct extends PhoneProdoct { }
class HuaweiPhoneProdoct extends PhoneProdoct { }
/**
* 抽象工厂
*/
abstract class AbstractProdoctFactory {
abstract createMacProdoct(): MacProdoct;
abstract createIWatchProdoct(): IWatchProdoct;
abstract createPhoneProdoct(): PhoneProdoct;
}
/**
* 具体产品工厂 - 苹果
*/
class AppleProdoct extends AbstractProdoctFactory {
createMacProdoct() {
return new AppleMacProdoct();
}
createIWatchProdoct() {
return new AppleIWatchProdoct();
}
createPhoneProdoct() {
return new ApplePhoneProdoct();
}
}
/**
* 具体产品工厂 - 华为
*/
class HuaweiProdoct extends AbstractProdoctFactory {
createMacProdoct() {
return new HuaweiMacProdoct();
}
createIWatchProdoct() {
return new HuaweiIWatchProdoct();
}
createPhoneProdoct() {
return new HuaweiPhoneProdoct();
}
}
let huaweiProduct = new HuaweiProdoct();
console.log(huaweiProduct.createMacProdoct()); // 购买华为电脑
console.log(huaweiProduct.createIWatchProdoct()); // 购买华为手表
console.log(huaweiProduct.createPhoneProdoct()); // 购买华为手机
优点
例如以上增加一个产品族比较方便,例如再创建一个小米,或者一个联想;
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。 抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
缺点
在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。