跳至主要內容

抽象工厂模式

约 688 字

抽象工厂模式

核心思想

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

典型用例

切换环境

抽象工厂模式可以用来切换不同的环境而无需修改客户端代码,例如:在测试环境中,使用模拟对象;而在生产环境中,使用实际对象。

// npm run code src/code/design-pattern/abstract-factory/switch-environment.ts

export {};

// 定义一些“产品”接口
interface DatabaseConnection {
    query(sql: string): any;
}

interface Logger {
    log(message: string): void;
}

// 创建具体的产品实现类
// 生产环境的实现
class ProductionDatabaseConnection implements DatabaseConnection {
    query(sql: string): any {
        // 实现数据库查询逻辑
        console.log(`Executing SQL on production database: ${sql}`);
    }
}

class ProductionLogger implements Logger {
    log(message: string): void {
        // 实现日志记录逻辑
        console.log(`Logging in production: ${message}`);
    }
}

// 测试环境的实现(模拟对象)
class MockDatabaseConnection implements DatabaseConnection {
    query(sql: string): any {
        console.log(`Mock query executed: ${sql}`);
    }
}

class MockLogger implements Logger {
    log(message: string): void {
        console.log(`Mock log: ${message}`);
    }
}

// 定义一个抽象工厂接口,它包含创建所有不同类型产品的方法
interface AbstractFactory {
    createDatabaseConnection(): DatabaseConnection;
    createLogger(): Logger;
}

// 创建具体的工厂类
class ProductionEnvironmentFactory implements AbstractFactory {
    createDatabaseConnection(): DatabaseConnection {
        return new ProductionDatabaseConnection();
    }

    createLogger(): Logger {
        return new ProductionLogger();
    }
}

class TestEnvironmentFactory implements AbstractFactory {
    createDatabaseConnection(): DatabaseConnection {
        return new MockDatabaseConnection();
    }

    createLogger(): Logger {
        return new MockLogger();
    }
}

function clientCode(factory: AbstractFactory): void {
    const dbConnection = factory.createDatabaseConnection();
    const logger = factory.createLogger();

    dbConnection.query("SELECT * FROM users");
    logger.log("Query executed.");
}

// 生产环境
const productionFactory = new ProductionEnvironmentFactory();
clientCode(productionFactory);

// 测试环境
const testFactory = new TestEnvironmentFactory();
clientCode(testFactory);

替换依赖关系

抽象工厂模式允许产生一系列相关或依赖对象,而无需指定具体的类。

在这个例子中,创建了一个抽象工厂来处理不同的数据库访问和消息传递。这样,当需要更换整个产品族时(数据库访问和消息传递),只需要更换工厂实现即可,而无需修改客户端代码。

// npm run code src/code/design-pattern/abstract-factory/substitution-dependency.ts

export {};

// 抽象产品:数据库连接
interface DatabaseConnection {
    connect(): void;
}

// 具体产品:MySQL连接
class MySQLConnection implements DatabaseConnection {
    connect() {
        console.log("Connected to MySQL database.");
    }
}

// 具体产品:PostgreSQL连接
class PostgreSQLConnection implements DatabaseConnection {
    connect() {
        console.log("Connected to PostgreSQL database.");
    }
}

// 抽象产品:消息传递
interface MessageService {
    sendMessage(message: string): void;
}

// 具体产品:邮件服务
class EmailService implements MessageService {
    sendMessage(message: string) {
        console.log(`Email: ${message}`);
    }
}

// 具体产品:SMS服务
class SMSService implements MessageService {
    sendMessage(message: string) {
        console.log(`SMS: ${message}`);
    }
}

// 抽象工厂
interface AbstractFactory {
    createDatabaseConnection(): DatabaseConnection;
    createMessageService(): MessageService;
}

// 具体工厂:生产MySQL和邮件服务的产品
class MySQLAndEmailFactory implements AbstractFactory {
    createDatabaseConnection(): DatabaseConnection {
        return new MySQLConnection();
    }
    createMessageService(): MessageService {
        return new EmailService();
    }
}

// 具体工厂:生产PostgreSQL和SMS服务的产品
class PostgreSQLAndSMSFactory implements AbstractFactory {
    createDatabaseConnection(): DatabaseConnection {
        return new PostgreSQLConnection();
    }
    createMessageService(): MessageService {
        return new SMSService();
    }
}

function clientCode(factory: AbstractFactory) {
    const dbConnection = factory.createDatabaseConnection();
    dbConnection.connect();

    const messageService = factory.createMessageService();
    messageService.sendMessage("Hello World");
}

// 使用MySQL和邮件服务的工厂
clientCode(new MySQLAndEmailFactory());

// 使用PostgreSQL和SMS服务的工厂
clientCode(new PostgreSQLAndSMSFactory());

跨平台组件

抽象工厂模式可以用来根据不同的操作系统创建适应其风格的UI组件,同时保持客户端代码的一致性。

// npm run code src/code/design-pattern/abstract-factory/cross-platform.ts

export {};

// 抽象产品:窗口
interface MyWindow {
    render(): void;
}

// 抽象产品:按钮
interface Button {
    render(): void;
}

// 抽象产品:文本框
interface TextBox {
    render(): void;
}

// Windows风格的具体产品
class WindowsWindow implements MyWindow {
    render() {
        console.log("Rendering Windows style window.");
    }
}

class WindowsButton implements Button {
    render() {
        console.log("Rendering Windows style button.");
    }
}

class WindowsTextBox implements TextBox {
    render() {
        console.log("Rendering Windows style text box.");
    }
}

// MacOS风格的具体产品
class MacOSWindow implements MyWindow {
    render() {
    console.log("Rendering MacOS style window.");
    }
}

class MacOSButton implements Button {
    render() {
        console.log("Rendering MacOS style button.");
    }
}

class MacOSTextBox implements TextBox {
    render() {
        console.log("Rendering MacOS style text box.");
    }
}

// 抽象工厂
interface UIFactory {
    createWindow(): MyWindow;
    createButton(): Button;
    createTextBox(): TextBox;
}

// 具体工厂:创建Windows风格的UI组件
class WindowsFactory implements UIFactory {
    createWindow(): MyWindow {
        return new WindowsWindow();
    }
    createButton(): Button {
        return new WindowsButton();
    }
    createTextBox(): TextBox {
        return new WindowsTextBox();
    }
}

// 具体工厂:创建MacOS风格的UI组件
class MacOSFactory implements UIFactory {
    createWindow(): MyWindow {
        return new MacOSWindow();
    }
    createButton(): Button {
        return new MacOSButton();
    }
    createTextBox(): TextBox {
        return new MacOSTextBox();
    }
}

function clientCode(factory: UIFactory) {
    const window = factory.createWindow();
    const button = factory.createButton();
    const textBox = factory.createTextBox();

    window.render();
    button.render();
    textBox.render();
}

// 使用Windows风格的UI工厂
clientCode(new WindowsFactory());

// 使用MacOS风格的UI工厂
clientCode(new MacOSFactory());

创建产品族

抽象工厂模式可以用来创建不同风格的UI产品族。

在这个例子中,每种风格将包含不同的按钮、滚动条和菜单组件。抽象工厂模式允许根据不同风格创建一系列可以一起工作的 UI 组件,可客户端代码不需要了解具体的组件实现。

如果需要添加新的风格系列,只需实现一个新的具体工厂和一系列具体产品即可。客户端代码只需要更换使用的工厂,无需进行其他修改,就能创建新风格的 UI 组件。这样,抽象工厂模式有效地支持了产品族的创建和易于扩展。

// npm run code src/code/design-pattern/abstract-factory/product-family.ts

export {};

// 抽象产品接口
interface Button {
    render(): void;
}

interface ScrollBar {
    render(): void;
}

interface Menu {
    render(): void;
}

// 现代风格的具体组件
class ModernButton implements Button {
    render() {
        console.log("Rendering a modern button.");
    }
}

class ModernScrollBar implements ScrollBar {
    render() {
        console.log("Rendering a modern scroll bar.");
    }
}

class ModernMenu implements Menu {
    render() {
        console.log("Rendering a modern menu.");
    }
}

// 经典风格的具体组件
class ClassicButton implements Button {
    render() {
        console.log("Rendering a classic button.");
    }
}

class ClassicScrollBar implements ScrollBar {
    render() {
        console.log("Rendering a classic scroll bar.");
    }
}

class ClassicMenu implements Menu {
    render() {
        console.log("Rendering a classic menu.");
    }
}

// 抽象工厂
interface UIFactory {
    createButton(): Button;
    createScrollBar(): ScrollBar;
    createMenu(): Menu;
}

// 现代风格的工厂
class ModernUIFactory implements UIFactory {
    createButton(): Button {
        return new ModernButton();
    }
    createScrollBar(): ScrollBar {
        return new ModernScrollBar();
    }
    createMenu(): Menu {
        return new ModernMenu();
    }
}

// 经典风格的工厂
class ClassicUIFactory implements UIFactory {
    createButton(): Button {
        return new ClassicButton();
    }
    createScrollBar(): ScrollBar {
        return new ClassicScrollBar();
    }
    createMenu(): Menu {
        return new ClassicMenu();
    }
}

function clientCode(factory: UIFactory) {
    const button = factory.createButton();
    const scrollBar = factory.createScrollBar();
    const menu = factory.createMenu();

    button.render();
    scrollBar.render();
    menu.render();
}

// 使用现代风格的UI工厂
clientCode(new ModernUIFactory());

// 使用经典风格的UI工厂
clientCode(new ClassicUIFactory());

配置产品组合

抽象工厂模式允许根据不同的配置或环境条件创建与之相匹配的对象组合,如不同语言的文本显示和消息处理。

在这个例子中,如果需要支持新的语言环境,只需添加一个新的具体工厂和相应的具体产品即可。客户端代码根据配置或环境条件选择相应的工厂,从而轻松实现多语言支持,而无需修改现有代码。这样,抽象工厂模式有效地支持了根据不同配置创建产品组合的需求。

// npm run code src/code/design-pattern/abstract-factory/configuration-portfolio.ts

export {};

// 抽象产品:文本显示
interface TextDisplay {
    display(text: string): void;
}

// 抽象产品:消息处理
interface MessageHandler {
    handleMessage(message: string): void;
}

// 英语环境的具体产品
class EnglishTextDisplay implements TextDisplay {
    display(text: string) {
        console.log(`Displaying in English: ${text}`);
    }
}

class EnglishMessageHandler implements MessageHandler {
    handleMessage(message: string) {
        console.log(`Handling English message: ${message}`);
    }
}

// 中文环境的具体产品
class ChineseTextDisplay implements TextDisplay {
    display(text: string) {
        console.log(`显示中文: ${text}`);
    }
}

class ChineseMessageHandler implements MessageHandler {
    handleMessage(message: string) {
        console.log(`处理中文消息: ${message}`);
    }
}

// 抽象工厂
interface LocalizationFactory {
    createTextDisplay(): TextDisplay;
    createMessageHandler(): MessageHandler;
}

// 英语环境的工厂
class EnglishLocalizationFactory implements LocalizationFactory {
    createTextDisplay(): TextDisplay {
        return new EnglishTextDisplay();
    }
    createMessageHandler(): MessageHandler {
        return new EnglishMessageHandler();
    }
}

// 中文环境的工厂
class ChineseLocalizationFactory implements LocalizationFactory {
    createTextDisplay(): TextDisplay {
        return new ChineseTextDisplay();
    }
    createMessageHandler(): MessageHandler {
        return new ChineseMessageHandler();
    }
}

function clientCode(factory: LocalizationFactory) {
    const textDisplay = factory.createTextDisplay();
    const messageHandler = factory.createMessageHandler();

    textDisplay.display("Hello World");
    messageHandler.handleMessage("This is a test message");
}

// 使用英语环境的工厂
clientCode(new EnglishLocalizationFactory());

// 使用中文环境的工厂
clientCode(new ChineseLocalizationFactory());

上次编辑于: