JavaScript工厂模式实战:从简单工厂到抽象工厂的蜕变

45 阅读4分钟

什么是工厂模式?

工厂模式就是将创建对象的过程单独封装。它像一条生产线,你告诉工厂需要什么样的产品,工厂就负责按照规格生产出来。

工厂模式的类型

1. 简单工厂模式

基本概念

简单工厂是最基础的工厂模式,通过一个 工厂类 根据传入的参数创建不同的对象。

想象一下,你在开发一个系统界面,需要一些按钮组件。这时你不需要自己去写每个按钮的具体实现,而是告诉按钮工厂:"我需要一个Windows风格的按钮",工厂ButtonFactory就会给你返回一个符合要求的按钮组件。

代码实现

// 基础按钮类
class Button {
    constructor(theme) {
        this.theme = theme;
    }   
    render() {
        return `渲染一个普通按钮`;
    }
}

// Windows风格按钮
class WindowsButton extends Button {
    render() {
        return `渲染一个 Windows 风格的按钮`;
    }
}

// Mac风格按钮
class MacButton extends Button {
    render() {
        return `渲染一个 Mac 风格的按钮`;
    }
}

// 按钮工厂:专注于单一职责 - 创建按钮
class ButtonFactory {
    static createButton(theme) {
        switch(theme) {
            case 'windows':
                return new WindowsButton(theme);
            case 'mac':
                return new MacButton(theme);
            default:
                return new Button(theme);
        }
    }
}

使用示例

const windowsBtn = ButtonFactory.createButton('windows');
console.log(windowsBtn.render()); // 输出:渲染一个 Windows 风格的按钮

2. 从简单工厂到抽象工厂的演进

简单工厂的局限性

随着业务的发展,我们发现单一的按钮工厂已经不能满足需求了。想象一下,你正在开发一个完整的系统界面:

  1. 最初,你只需要创建按钮,使用简单工厂就足够了
  2. 但很快,你发现需要创建更多的UI组件:
    • 按钮(Button)
    • 输入框(Input)
    • 下拉菜单(Select)
    • 对话框(Dialog) ...等等

更重要的是,这些组件必须保持统一的设计风格。比如当你选择了Windows风格,所有组件都应该是Windows风格的。这就好比你在开发一个完整的UI组件库,而不是零散地生产单个组件。

这时候,我们需要一个更强大的工厂系统,它能够:

  1. 统一管理多种类型的UI组件
  2. 确保所有组件风格的一致性
  3. 方便未来扩展新的组件类型

这就是抽象工厂模式诞生的背景。

3、抽象工厂模式

抽象工厂模式会提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

这句话猛然之间好像不太好理解,你就记住抽象工厂(AbstractFactory)是用来定规矩的,抽象工厂不干活,具体工厂(ConcreteFactory)来干活!

当你需要一套特定风格(比如Windows风格)的UI组件时,抽象工厂会确保为你创建的所有组件(按钮、输入框等)都保持相同的设计风格。

// 抽象工厂:定义创建产品的标准接口
class UIFactory {
    createButton() {
        throw new Error('必须实现createButton方法');
    }
    
    createInput() {
        throw new Error('必须实现createInput方法');
    }
}

// Windows风格工厂
class WindowsUIFactory extends UIFactory {
    createButton() {
        return new WindowsButton();
    }
    
    createInput() {
        return new WindowsInput();
    }
}


// 使用示例 
const windowsFactory = new WindowsUIFactory(); 
const button = windowsFactory.createButton(); // 正常工作 
const input = windowsFactory.createInput(); // 正常工作 

// 错误的使用方式 
const baseFactory = new UIFactory(); 
baseFactory.createButton(); // 错误:必须实现createButton方法

在基类 UIFactory 中, createButtoncreateInput 是一个抽象方法,这种设计相当于在说:"这个方法必须被子类重写,不能直接使用父类的方法",工厂方法模式的核心就是让子类决定具体要创建什么类型(风格)的对象。如果子类不实现这个方法,整个模式的目的就无法达成,种设计确保了工厂方法模式的完整性,防止了半成品工厂的产生。

假如有一天,Windows风格的产品过气了,我们需要产出一款新风格UI投入市场,这时候怎么办?我们不需要对抽象工厂UIFactory做任何修改,只需要拓展它的种类:

// Mac风格工厂
class MacUIFactory extends UIFactory {
    createButton() {
        return new MacButton();
    }
    
    createInput() {
        return new MacInput();
    }
}

这个操作对原有的产品风格不会造成任何潜在影响 ,遵守开放封闭原则 ——— “对拓展开放,对修改封闭”。

两种类型的对比

简单工厂

  • 优点:实现简单,使用方便
  • 缺点:扩展性差,不适合创建相关产品族
  • 适用场景 :产品种类较少且相对稳定

抽象工厂

  • 优点:可以创建产品族,扩展性好
  • 缺点:类的数量增多,结构相对复杂
  • 适用场景 :需要创建一系列相关产品

总结

工厂模式的演进过程反映了软件设计中一个重要的原则: 从简单到复杂,从具体到抽象 。当简单工厂无法满足需求时,我们就需要考虑使用抽象工厂来处理更复杂的对象创建场景。选择哪种模式,关键是要根据实际业务需求和未来可能的变化来决定。好的设计模式应该能够帮助我们写出更加优雅、可维护的代码。