webpack2源码工厂模式

81 阅读6分钟

工厂模式是一种创建型模式,就像其名字一样,工厂对外创建生成一批对象。这些对象具有一些相似性,这些对象具有一些对外的相同接口,如都有paint方法。工厂模式不修改原有的代码,通过添加额外功能的类扩展功能。如何生产对象包含以下3种方式:

  1. 简单工厂模式 把对象的创建放到一个工厂类中,通过参数来创建不同的对象。
  2. 工厂方法模式 在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。同一种物品扩展不同的物品类型,通过添加子类实现。如Button,已经有Windows Button子类,想增加一个Web Button类,增加一个子类Web Button类。
  3. 抽象工厂模式 定义一个创建一系列相关或互相依赖对象的接口,抽象出工厂类。可以增加扩展新的工厂类。这种模式处理更复杂的对象关系,多种不同的物品对应不同的类型。抽象工厂模式比工厂方法模式更向上一层抽象,加一层向上的分类。 如有Button,Checkbox这两种组件,会在Windows,Mac平台上展示。则有4种组合可能,Windows Button,Windows Checkbox,Mac Button,Mac Checkbox。抽象出平台接口,Windows和Mac两类,然后分别处理每一平台的不同的组件创建。

工厂方法模式

340271355-95f67fc4-a452-4e04-8467-bfddaece25bd.png

  1. 产品 (Product) 将会对接口进行声明。 对于所有由创建者及其子类构建的对象, 这些接口都是通用的。
  2. 具体产品 (Concrete Products) 是产品接口的不同实现。
  3. 创建者 (Creator) 类声明返回产品对象的工厂方法。 该方法的返回对象类型必须与产品接口相匹配。
  4. 具体创建者 (Concrete Creators) 将会重写基础工厂方法, 使其返回不同类型的产品。

例子:

// 创建者类声明的工厂方法必须返回一个产品类的对象。创建者的子类通常会提供
// 该方法的实现。
class Dialog is
    // 创建者还可提供一些工厂方法的默认实现。
    abstract method createButton():Button

    // 请注意,创建者的主要职责并非是创建产品。其中通常会包含一些核心业务
    // 逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方
    // 法并使其返回不同类型的产品来间接修改业务逻辑。
    method render() is
        // 调用工厂方法创建一个产品对象。
        Button okButton = createButton()
        // 现在使用产品。
        okButton.onClick(closeDialog)
        okButton.render()


// 具体创建者将重写工厂方法以改变其所返回的产品类型。
class WindowsDialog extends Dialog is
    method createButton():Button is
        return new WindowsButton()

class WebDialog extends Dialog is
    method createButton():Button is
        return new HTMLButton()


// 产品接口中将声明所有具体产品都必须实现的操作。
interface Button is
    method render()
    method onClick(f)

// 具体产品需提供产品接口的各种实现。
class WindowsButton implements Button is
    method render(a, b) is
        // 根据 Windows 样式渲染按钮。
    method onClick(f) is
        // 绑定本地操作系统点击事件。

class HTMLButton implements Button is
    method render(a, b) is
        // 返回一个按钮的 HTML 表述。
    method onClick(f) is
        // 绑定网络浏览器的点击事件。


class Application is
    field dialog: Dialog

    // 程序根据当前配置或环境设定选择创建者的类型。
    method initialize() is
        config = readApplicationConfigFile()

        if (config.OS == "Windows") then
            dialog = new WindowsDialog()
        else if (config.OS == "Web") then
            dialog = new WebDialog()
        else
            throw new Exception("错误!未知的操作系统。")

    // 当前客户端代码会与具体创建者的实例进行交互,但是必须通过其基本接口
    // 进行。只要客户端通过基本接口与创建者进行交互,你就可将任何创建者子
    // 类传递给客户端。
    method main() is
        this.initialize()
        dialog.render()

抽象工厂模式

340270089-1a21e4c2-c648-4ace-992b-ffbbf83cda94.png

  1. 抽象产品 (Abstract Product) 为构成系列产品的一组不同但相关的产品声明接口。
  2. 具体产品 (Concrete Product) 是抽象产品的多种不同类型实现。
  3. 抽象工厂 (Abstract Factory) 接口声明了一组创建各种抽象产品的方法。
  4. 具体工厂 (Concrete Factory) 实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。

例子:

// 抽象工厂接口声明了一组能返回不同抽象产品的方法。这些产品属于同一个系列
// 且在高层主题或概念上具有相关性。同系列的产品通常能相互搭配使用。系列产
// 品可有多个变体,但不同变体的产品不能搭配使用。
interface GUIFactory is
    method createButton():Button
    method createCheckbox():Checkbox


// 具体工厂可生成属于同一变体的系列产品。工厂会确保其创建的产品能相互搭配
// 使用。具体工厂方法签名会返回一个抽象产品,但在方法内部则会对具体产品进
// 行实例化。
class WinFactory implements GUIFactory is
    method createButton():Button is
        return new WinButton()
    method createCheckbox():Checkbox is
        return new WinCheckbox()

// 每个具体工厂中都会包含一个相应的产品变体。
class MacFactory implements GUIFactory is
    method createButton():Button is
        return new MacButton()
    method createCheckbox():Checkbox is
        return new MacCheckbox()


// 系列产品中的特定产品必须有一个基础接口。所有产品变体都必须实现这个接口。
interface Button is
    method paint()

// 具体产品由相应的具体工厂创建。
class WinButton implements Button is
    method paint() is
        // 根据 Windows 样式渲染按钮。

class MacButton implements Button is
    method paint() is
        // 根据 macOS 样式渲染按钮

// 这是另一个产品的基础接口。所有产品都可以互动,但是只有相同具体变体的产
// 品之间才能够正确地进行交互。
interface Checkbox is
    method paint()

class WinCheckbox implements Checkbox is
    method paint() is
        // 根据 Windows 样式渲染复选框。

class MacCheckbox implements Checkbox is
    method paint() is
        // 根据 macOS 样式渲染复选框。

// 客户端代码仅通过抽象类型(GUIFactory、Button 和 Checkbox)使用工厂
// 和产品。这让你无需修改任何工厂或产品子类就能将其传递给客户端代码。
class Application is
    private field factory: GUIFactory
    private field button: Button
    constructor Application(factory: GUIFactory) is
        this.factory = factory
    method createUI() is
        this.button = factory.createButton()
    method paint() is
        button.paint()


// 程序会根据当前配置或环境设定选择工厂类型,并在运行时创建工厂(通常在初
// 始化阶段)。
class ApplicationConfigurator is
    method main() is
        config = readApplicationConfigFile()

        if (config.OS == "Windows") then
            factory = new WinFactory()
        else if (config.OS == "Mac") then
            factory = new MacFactory()
        else
            throw new Exception("错误!未知的操作系统。")

        Application app = new Application(factory)

webpack工厂方法模式

// Compilation.js
_addModuleChain(context, dependency, onModule, callback) {
    // ...
    // 工厂方法模式
    const moduleFactory = this.dependencyFactories.get(Dep);
    moduleFactory.create(...); // XxxModuleFactory
}

其中dependencyFactories可能会获取到多种模块工厂(normalModuleFactory、dllModuleFactory、multiModuleFactory)。 normalModuleFactory、dllModuleFactory、multiModuleFactory对外提供统一create接口,用于创建对应类型的module对象。 normalModule、dllModule、multiModule都继承了Module类,共同有Module类的方法,并且各自实现了一些相同的方法(如build方法),外部接口调用时统一调用,不用区分module类型。