设计模式(二):工厂模式

一,什么是工厂模式

工厂模式(Factory Pattern) 是一种创建型设计模式,它定义了一个用于创建对象的接口,而不需要显式地指定对象所属的具体类。换句话说,工厂模式将对象的实例化过程延迟到子类或其他工厂方法中,通过工厂方法来创建对象而不是直接调用构造函数。

工厂模式的核心思想是将对象创建的细节隐藏在工厂方法中,从而让代码具有更好的扩展性和可维护性

  • 解耦对象的创建和使用:当你想要将对象的创建与其使用分离时,工厂模式很有用。这样可以提高代码的灵活性和可维护性。
  • 处理复杂的创建逻辑:当创建一个对象需要复杂的逻辑时,工厂模式可以将该逻辑封装在工厂方法中,从而简化代码。
  • 创建不同类型的对象:当你需要创建不同类型的对象,并且代码不需要知道这些对象的具体类型时,工厂模式很有用。
  • 支持多态:工厂模式可以通过返回抽象产品类型的对象来支持多态,从而使代码更加通用和灵活。

工厂模式在实际开发中有很多应用场景,下面是一些例子:

  1. 数据库连接工厂:在Web应用程序中,我们可能需要连接到不同类型的数据库(MySQL、PostgreSQL、MongoDB等)。使用工厂模式创建一个工厂类来封装创建数据库连接的逻辑,从而使客户端代码独立于具体的数据库实现。
  2. UI组件工厂:在GUI应用程序中,可以使用工厂模式来创建不同类型的UI组件,如按钮、文本框、下拉列表等。工厂类可以根据用户的输入或配置,返回合适的UI组件实例。
  3. 日志记录工厂:在应用程序中,我们可能需要使用不同的日志记录机制,如控制台输出、文件日志、 Syslog 等。使用工厂模式可以创建一个日志工厂,根据配置返回合适的日志记录器实例。
  4. 支付网关工厂:在电子商务应用程序中,可能需要支持多种支付方式,如信用卡、PayPal、Apple Pay等。使用工厂模式可以创建一个支付网关工厂,根据用户选择的支付方式返回相应的支付网关实例。
  5. 文件读写工厂:在处理文件I/O操作时,可以使用工厂模式创建不同类型的文件读写器,如CSV读写器、XML读写器、PDF读写器等。这样可以将文件格式的处理逻辑封装在工厂类中,使客户端代码更加灵活和可扩展。
  6. 游戏角色工厂:在游戏开发中,可以使用工厂模式来创建不同类型的游戏角色,如战士、法师、弓箭手等。每种角色都有不同的属性和技能,工厂类可以根据需求创建合适的角色实例。
  7. 报告生成器工厂:在企业应用程序中,可能需要生成各种类型的报告,如销售报告、财务报告、库存报告等。使用工厂模式可以创建一个报告生成器工厂,根据报告类型返回合适的报告生成器实例。

工厂模式的分类:

  • 简单工厂模式(Simple Factory Pattern):通过一个工厂类来决定实例化哪个类的对象,通常使用一个静态方法。

  • 工厂方法模式(Factory Method Pattern):将对象的实例化延迟到子类,通过子类重写的工厂方法来创建具体对象。

  • 抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建一系列相关或依赖的对象,而无需指定它们的具体类。抽象工厂模式通常用来生产一系列产品,这些产品通常是关联在一起的,比如一整套家具中的桌子和椅子。

为什么会出现这三种工厂模式?

  1. 简单性与灵活性的权衡:
    - 简单工厂模式提供了一种简单易用的创建对象的方式,但当需求变化时,修改工厂类会很困难。
    - 工厂方法模式通过将对象的创建推迟到子类,提供了更大的灵活性,但增加了代码量。

  2. 产品种类的增加:
    - 当产品种类较少时,简单工厂模式可以很好地满足需求。
    - 但当产品种类不断增加时,工厂方法模式可以更好地应对这种变化,通过引入工厂子类来创建不同类型的产品。

  3. 产品之间的依赖关系:
    - 当产品之间存在相互依赖或相关的关系时,简单工厂模式和工厂方法模式可能无法很好地处理这种情况。
    - 抽象工厂模式通过提供一个创建相关产品家族的接口,更好地解决了这个问题。

二,python代码

(一)简单工厂模式

class Car:
    def __init__(self, model):
        self.model = model

    def drive(self):
        pass

class Sedan(Car):
    def drive(self):
        return f"驾驶 {self.model} 轿车"

class SUV(Car):
    def drive(self):
        return f"驾驶 {self.model} SUV"

class CarFactory:
    @staticmethod
    def create_car(car_type, model):
        if car_type == "sedan":
            return Sedan(model)
        elif car_type == "suv":
            return SUV(model)
        else:
            raise ValueError("不支持的车型")

# 使用简单工厂
factory = CarFactory()
sedan = factory.create_car("sedan", "Toyota Camry")
suv = factory.create_car("suv", "Honda CR-V")

print(sedan.drive())  # 输出: 驾驶 Toyota Camry 轿车
print(suv.drive())    # 输出: 驾驶 Honda CR-V SUV

(二)工厂方法模式

from abc import ABC, abstractmethod

class Car(ABC):
    @abstractmethod
    def drive(self):
        pass

class Sedan(Car):
    def drive(self):
        return "驾驶轿车"

class SUV(Car):
    def drive(self):
        return "驾驶SUV"

class CarFactory(ABC):
    @abstractmethod
    def create_car(self):
        pass

class SedanFactory(CarFactory):
    def create_car(self):
        return Sedan()

class SUVFactory(CarFactory):
    def create_car(self):
        return SUV()

# 使用工厂方法
sedan_factory = SedanFactory()
suv_factory = SUVFactory()

sedan = sedan_factory.create_car()
suv = suv_factory.create_car()

print(sedan.drive())  # 输出: 驾驶轿车
print(suv.drive())    # 输出: 驾驶SUV

(三)抽象工厂模式

from abc import ABC, abstractmethod

# 抽象产品
class Car(ABC):
    @abstractmethod
    def drive(self):
        pass

class Engine(ABC):
    @abstractmethod
    def start(self):
        pass

# 具体产品
class SedanCar(Car):
    def drive(self):
        return "驾驶轿车"

class SUVCar(Car):
    def drive(self):
        return "驾驶SUV"

class GasolineEngine(Engine):
    def start(self):
        return "启动汽油发动机"

class ElectricEngine(Engine):
    def start(self):
        return "启动电动发动机"

# 抽象工厂
class CarFactory(ABC):
    @abstractmethod
    def create_car(self):
        pass

    @abstractmethod
    def create_engine(self):
        pass

# 具体工厂
class SedanGasolineFactory(CarFactory):
    def create_car(self):
        return SedanCar()

    def create_engine(self):
        return GasolineEngine()

class SUVElectricFactory(CarFactory):
    def create_car(self):
        return SUVCar()

    def create_engine(self):
        return ElectricEngine()

# 使用抽象工厂
sedan_gasoline_factory = SedanGasolineFactory()
suv_electric_factory = SUVElectricFactory()

sedan = sedan_gasoline_factory.create_car()
sedan_engine = sedan_gasoline_factory.create_engine()

suv = suv_electric_factory.create_car()
suv_engine = suv_electric_factory.create_engine()

print(sedan.drive())        # 输出: 驾驶轿车
print(sedan_engine.start()) # 输出: 启动汽油发动机
print(suv.drive())          # 输出: 驾驶SUV
print(suv_engine.start())   # 输出: 启动电动发动机

三,JavaScript代码

(一)简单工厂模式

class Car {
  constructor(model) {
    this.model = model;
  }
}

class SimpleCatFactory {
  createCar(model) {
    switch (model) {
      case 'SUV':
        return new Car('SUV');
      case 'Sedan':
        return new Car('Sedan');
      default:
        throw new Error('Unknown car model');
    }
  }
}

// 使用简单工厂
const simpleFactory = new SimpleCatFactory();
const suv = simpleFactory.createCar('SUV');
console.log(suv.model); // 输出: SUV

(二)工厂方法模式

class CarFactory {
  createCar() {
    throw new Error('This method should be overridden');
  }
}

class SUVFactory extends CarFactory {
  createCar() {
    return new Car('SUV');
  }
}

class SedanFactory extends CarFactory {
  createCar() {
    return new Car('Sedan');
  }
}

// 使用工厂方法
const suvFactory = new SUVFactory();
const sedanFactory = new SedanFactory();
const suv2 = suvFactory.createCar();
const sedan = sedanFactory.createCar();
console.log(suv2.model); // 输出: SUV
console.log(sedan.model); // 输出: Sedan

(三)抽象工厂模式

class Engine {
  constructor(type) {
    this.type = type;
  }
}

class Tire {
  constructor(type) {
    this.type = type;
  }
}

class AbstractCarFactory {
  createEngine() {
    throw new Error('This method should be overridden');
  }

  createTire() {
    throw new Error('This method should be overridden');
  }
}

class SUVFactory extends AbstractCarFactory {
  createEngine() {
    return new Engine('SUV Engine');
  }

  createTire() {
    return new Tire('SUV Tire');
  }
}

class SedanFactory extends AbstractCarFactory {
  createEngine() {
    return new Engine('Sedan Engine');
  }

  createTire() {
    return new Tire('Sedan Tire');
  }
}

// 使用抽象工厂
const suvFactory2 = new SUVFactory();
const sedanFactory2 = new SedanFactory();

const suvEngine = suvFactory2.createEngine();
const suvTire = suvFactory2.createTire();
console.log(suvEngine.type); // 输出: SUV Engine
console.log(suvTire.type); // 输出: SUV Tire

const sedanEngine = sedanFactory2.createEngine();
const sedanTire = sedanFactory2.createTire();
console.log(sedanEngine.type); // 输出: Sedan Engine
console.log(sedanTire.type); // 输出: Sedan Tire

四,实际应用

(一)python代码

1,配置管理系统

问题:在不同环境(开发、生产)中需要不同的配置设置。
解决方案:使用简单工厂来创建适合特定环境的配置对象。

# 场景:配置管理系统

class Configuration:
    def __init__(self, settings):
        self.settings = settings

    def get_setting(self, key):
        return self.settings.get(key)


class ConfigurationFactory:
    @staticmethod
    def create_configuration(env):
        if env == "development":
            return Configuration({"debug": True})
        elif env == "production":
            return Configuration({"debug": False})
        else:
            raise ValueError("Invalid environment")


# 使用简单工厂
dev_config = ConfigurationFactory.create_configuration("development")
print(dev_config.get_setting("debug"))  # 输出: True

优点:

- 集中管理配置创建逻辑,便于维护。
- 客户端代码不需要知道具体的配置实现细节。

缺点:

- 如果需要添加新的环境配置,需要修改工厂类。

适用场景:

- 配置项相对固定,不经常变动。
- 配置逻辑相对简单,不需要复杂的继承结构。

2,支付系统

问题:需要支持多种支付方式(如Stripe、PayPal),且可能需要经常添加新的支付方式。
解决方案:为每种支付处理器创建一个工厂类,通过工厂方法创建具体的支付处理器。

# 场景:支付系统

from abc import ABC, abstractmethod


class PaymentProcessor(ABC):
    @abstractmethod
    def process_payment(self, amount):
        pass


class StripeProcessor(PaymentProcessor):
    def process_payment(self, amount):
        print(f"Processing ${amount} payment via Stripe")


class PayPalProcessor(PaymentProcessor):
    def process_payment(self, amount):
        print(f"Processing ${amount} payment via PayPal")


class PaymentProcessorFactory(ABC):
    @abstractmethod
    def create_processor(self):
        pass


class StripeProcessorFactory(PaymentProcessorFactory):
    def create_processor(self):
        return StripeProcessor()


class PayPalProcessorFactory(PaymentProcessorFactory):
    def create_processor(self):
        return PayPalProcessor()


# 使用工厂方法
stripe_factory = StripeProcessorFactory()
stripe_processor = stripe_factory.create_processor()
stripe_processor.process_payment(100)  # 输出: Processing $100 payment via Stripe

优点:

- 易于扩展新的支付方式,只需添加新的处理器类和对应的工厂类。
- 符合开闭原则,不需要修改现有代码就可以添加新的支付方式。

缺点:

- 可能会导致类的数量增加,每种支付方式都需要一个工厂类。

适用场景:

- 系统需要经常添加新的产品类型。
- 产品的创建逻辑比较复杂,需要独立的工厂类来管理。

3,跨平台 UI 组件库

问题:需要创建一套完整的、风格一致的 UI 组件,且这些组件需要在不同的操作系统上有不同的外观。
解决方案:使用抽象工厂来创建一系列相关的 UI 组件,为每个平台提供一个具体的工厂。

# 场景:跨平台 UI 组件库

class Button(ABC):
    @abstractmethod
    def paint(self):
        pass

class MacButton(Button):
    def paint(self):
        return "Rendering a button in macOS style"

class WindowsButton(Button):
    def paint(self):
        return "Rendering a button in Windows style"

class Checkbox(ABC):
    @abstractmethod
    def paint(self):
        pass

class MacCheckbox(Checkbox):
    def paint(self):
        return "Rendering a checkbox in macOS style"

class WindowsCheckbox(Checkbox):
    def paint(self):
        return "Rendering a checkbox in Windows style"

class GUIFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass

    @abstractmethod
    def create_checkbox(self):
        pass

class MacFactory(GUIFactory):
    def create_button(self):
        return MacButton()

    def create_checkbox(self):
        return MacCheckbox()

class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()

    def create_checkbox(self):
        return WindowsCheckbox()

# 使用抽象工厂
def create_ui(factory):
    button = factory.create_button()
    checkbox = factory.create_checkbox()
    print(button.paint())
    print(checkbox.paint())

mac_factory = MacFactory()
create_ui(mac_factory)
# 输出:
# Rendering a button in macOS style
# Rendering a checkbox in macOS style

优点:

- 确保创建的 UI 组件之间风格一致。
- 易于切换整个产品族(如从 Windows 风格切换到 macOS 风格)。

缺点:

- 如果需要添加新的 UI 组件类型(如 RadioButton),需要修改所有的工厂类。

适用场景:

- 需要创建一系列相关或相互依赖的对象。
- 系统需要与多个产品族一起工作,但每次只使用其中一个。

(二)JavaScript代码

1,前端日志记录系统

前端:

function initDB() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('LogDatabase', 1);

        request.onupgradeneeded = (event) => {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('logs')) {
                db.createObjectStore('logs', {autoIncrement: true});
            }
        };

        request.onsuccess = (event) => {
            resolve(event.target.result);
        };

        request.onerror = (event) => {
            reject('Database error: ' + event.target.errorCode);
        };
    });
}


class Logger {
    constructor(db) {
        this.db = db;
    }

    // 记录日志信息到 IndexedDB
    log(message, level = 'info') {
        const logEntry = {
            timestamp: new Date().toISOString(),
            level: level.toUpperCase(),
            message,
        };

        const transaction = this.db.transaction(['logs'], 'readwrite');
        const store = transaction.objectStore('logs');
        store.add(logEntry);

        console.log(`[${logEntry.timestamp}] [${logEntry.level}]: ${logEntry.message}`);
    }

    info(message) {
        this.log(message, 'info');
    }

    warning(message) {
        this.log(message, 'warning');
    }

    error(message) {
        this.log(message, 'error');
    }

    debug(message) {
        this.log(message, 'debug');
    }

    // 从 IndexedDB 中读取所有日志并生成文本文件
    async getLogsAsText() {
        return new Promise((resolve, reject) => {
            const transaction = this.db.transaction(['logs'], 'readonly');
            const store = transaction.objectStore('logs');
            const request = store.getAll();

            request.onsuccess = (event) => {
                const logs = event.target.result;
                const logText = logs.map(log => `[${log.timestamp}] [${log.level}]: ${log.message}`).join('\n');
                resolve(logText);
            };

            request.onerror = (event) => {
                reject('Failed to retrieve logs: ' + event.target.errorCode);
            };
        });
    }

    // 上传日志到服务器并重试三次
    async uploadLogs(serverUrl, retryCount = 3) {
        try {
            const logText = await this.getLogsAsText();
            const logBlob = new Blob([logText], {type: 'text/plain'});
            const formData = new FormData();
            formData.append('file', logBlob, 'logs.txt');

            const response = await fetch(serverUrl, {
                method: 'POST',
                body: formData,
            });

            if (response.ok) {
                console.log('Logs uploaded successfully');
                this.clearLogs(); // 上传成功后清除日志
            } else {
                throw new Error(`Failed to upload logs: ${response.statusText}`);
            }
        } catch (error) {
            console.error(error);
            if (retryCount > 0) {
                console.log(`Retrying... (${3 - retryCount + 1}/3)`);
                await this.uploadLogs(serverUrl, retryCount - 1);
            } else {
                console.error('Failed to upload logs after 3 attempts.');
            }
        }
    }

    // 清空 IndexedDB 中的日志
    clearLogs() {
        const transaction = this.db.transaction(['logs'], 'readwrite');
        const store = transaction.objectStore('logs');
        store.clear();
        console.log('Logs cleared from IndexedDB');
    }

    // 每天定时上传
    scheduleUpload(serverUrl) {
        const now = new Date();
        const nextUploadTime = new Date();
        nextUploadTime.setHours(1, 0, 0, 0); // 设置为第二天的凌晨 1:00

        if (now > nextUploadTime) {
            // 如果当前时间已经超过今天的 1:00,则设置为明天的 1:00
            nextUploadTime.setDate(nextUploadTime.getDate() + 1);
        }

        const timeUntilNextUpload = nextUploadTime.getTime() - now.getTime();
        console.log(`Next upload scheduled in ${(timeUntilNextUpload / 1000 / 60).toFixed(2)} minutes`);

        setTimeout(() => {
            this.uploadLogs(serverUrl);
            setInterval(() => {
                this.uploadLogs(serverUrl);
            }, 24 * 60 * 60 * 1000); // 每天上传一次
        }, timeUntilNextUpload);
    }
}


const config = {
    uploadLogs: true, // 配置项:是否上传日志
    serverUrl: 'https://example.com/upload', // 后端服务器地址
};

initDB().then(db => {
    const logger = new Logger(db);

    // 记录不同级别的日志
    logger.info('This is an info log.');
    logger.warning('This is a warning log.');
    logger.error('This is an error log.');
    logger.debug('This is a debug log.');

    // 每天定时上传日志
    if (config.uploadLogs) {
        logger.scheduleUpload(config.serverUrl);
    }
}).catch(error => {
    console.error('Failed to initialize IndexedDB:', error);
});

node.js 后端:

const express = require('express');
const multer = require('multer');
const app = express();
const port = 3000;

const upload = multer({dest: 'uploads/'}); // 上传文件的目录

app.post('/upload', upload.single('file'), (req, res) => {
    console.log('File uploaded:', req.file);
    res.status(200).send('File uploaded successfully');
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}`);
});
  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值