设计模式(C++/Qt)-工厂模式

在软件开发中,对象创建是基础但关键的任务------工厂模式提供了一种优雅的解决方案,让您的代码摆脱硬编码的依赖关系

一、为什么需要工厂模式?

在C++/Qt开发中,我们经常面临这样的困境:

  • 对象创建逻辑分散在代码各处
  • 新增类型需要修改多处代码
  • 对象依赖关系难以管理
  • 单元测试难以进行

工厂模式 通过封装对象创建过程,完美解决了这些问题。作为创建型设计模式的代表,它让您的代码更加灵活可扩展易于维护

二、工厂模式核心概念

工厂模式的核心思想是将对象的创建与使用分离,通过专门的"工厂"类来负责对象的实例化。在C++/Qt中,我们主要使用三种工厂模式:

1. 简单工厂模式(静态工厂)

适用场景:对象种类有限且不经常变化的情况

cpp 复制代码
// 抽象产品类
class Document : public QObject {
public:
    virtual void open() = 0;
    virtual void save() = 0;
};

// 具体产品类
class TextDocument : public Document {
public:
    void open() override { qDebug() << "Opening text document..."; }
    void save() override { qDebug() << "Saving text document..."; }
};

class SpreadsheetDocument : public Document {
public:
    void open() override { qDebug() << "Opening spreadsheet..."; }
    void save() override { qDebug() << "Saving spreadsheet..."; }
};

// 简单工厂
class DocumentFactory {
public:
    static Document* createDocument(const QString& type) {
        if (type == "Text") return new TextDocument;
        if (type == "Spreadsheet") return new SpreadsheetDocument;
        return nullptr;
    }
};

// 使用示例
Document* doc = DocumentFactory::createDocument("Text");
doc->open();
doc->save();
delete doc;

2. 工厂方法模式

适用场景:需要扩展新产品类型,且不希望修改现有代码

cpp 复制代码
// 抽象创建者
class DocumentCreator {
public:
    virtual Document* createDocument() = 0;
    
    void processDocument() {
        Document* doc = createDocument();
        doc->open();
        // 处理文档...
        doc->save();
        delete doc;
    }
};

// 具体创建者
class TextDocumentCreator : public DocumentCreator {
public:
    Document* createDocument() override {
        return new TextDocument();
    }
};

class SpreadsheetCreator : public DocumentCreator {
public:
    Document* createDocument() override {
        return new SpreadsheetDocument();
    }
};

// 使用示例
DocumentCreator* creator = new TextDocumentCreator();
creator->processDocument();  // 处理文本文档

3. 抽象工厂模式

适用场景:需要创建相关对象族(如不同主题的UI控件)

cpp 复制代码
// 抽象工厂
class ThemeFactory {
public:
    virtual QPushButton* createButton() = 0;
    virtual QSlider* createSlider() = 0;
};

// 亮色主题工厂
class LightThemeFactory : public ThemeFactory {
public:
    QPushButton* createButton() override {
        auto btn = new QPushButton("Light Button");
        btn->setStyleSheet("background-color: #f0f0f0; color: #333;");
        return btn;
    }
    
    QSlider* createSlider() override {
        auto slider = new QSlider(Qt::Horizontal);
        slider->setStyleSheet("QSlider::groove:horizontal { background: #e0e0e0; }");
        return slider;
    }
};

// 暗色主题工厂
class DarkThemeFactory : public ThemeFactory {
public:
    QPushButton* createButton() override {
        auto btn = new QPushButton("Dark Button");
        btn->setStyleSheet("background-color: #333; color: #f0f0f0;");
        return btn;
    }
    
    QSlider* createSlider() override {
        auto slider = new QSlider(Qt::Horizontal);
        slider->setStyleSheet("QSlider::groove:horizontal { background: #555; }");
        return slider;
    }
};

// 使用示例
void createUI(ThemeFactory* factory, QWidget* parent) {
    QPushButton* btn = factory->createButton();
    QSlider* slider = factory->createSlider();
    
    QVBoxLayout* layout = new QVBoxLayout(parent);
    layout->addWidget(btn);
    layout->addWidget(slider);
}

// 根据用户设置创建主题
ThemeFactory* factory = userPrefersDarkTheme ? 
    new DarkThemeFactory() : new LightThemeFactory();
createUI(factory, this);

三、Qt中工厂模式的典型应用场景

1. 插件系统开发

Qt的插件架构天然适合工厂模式:

cpp 复制代码
// 插件接口
class PluginInterface {
public:
    virtual QWidget* createToolWidget(QWidget* parent) = 0;
    virtual QString pluginName() const = 0;
};

// 主程序加载插件
void loadPlugins() {
    QDir pluginsDir(qApp->applicationDirPath() + "/plugins");
    
    foreach(QString fileName, pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject* plugin = loader.instance();
        if (plugin) {
            PluginInterface* pluginInterface = qobject_cast<PluginInterface*>(plugin);
            if (pluginInterface) {
                QWidget* tool = pluginInterface->createToolWidget(this);
                // 添加到界面...
            }
        }
    }
}

2. 跨平台组件创建

cpp 复制代码
class NativeDialog {
public:
    virtual void show() = 0;
};

#ifdef Q_OS_WIN
class WinFileDialog : public NativeDialog {
public:
    void show() override { /* Windows原生实现 */ }
};
#elif defined(Q_OS_MAC)
class MacFileDialog : public NativeDialog {
public:
    void show() override { /* macOS原生实现 */ }
};
#endif

class DialogFactory {
public:
    static NativeDialog* createFileDialog() {
        #ifdef Q_OS_WIN
            return new WinFileDialog;
        #elif defined(Q_OS_MAC)
            return new MacFileDialog;
        #else
            return nullptr; // 其他平台
        #endif
    }
};

3. 动态对象创建(序列化/反序列化)

cpp 复制代码
class SerializableObject : public QObject {
public:
    virtual void serialize(QDataStream& out) = 0;
    virtual void deserialize(QDataStream& in) = 0;
    virtual QString typeName() const = 0;
};

class ObjectFactory {
public:
    static SerializableObject* createObject(const QString& type) {
        if (type == "Circle") return new Circle;
        if (type == "Rectangle") return new Rectangle;
        return nullptr;
    }
    
    static SerializableObject* loadFromStream(QDataStream& in) {
        QString type;
        in >> type;
        
        SerializableObject* obj = createObject(type);
        if (obj) obj->deserialize(in);
        return obj;
    }
};

四、工厂模式的优缺点分析

✅ 优点:

  1. 解耦对象创建:将创建逻辑与业务逻辑分离
  2. 提高可扩展性:新增产品类型无需修改客户端代码
  3. 统一管理创建过程:集中控制对象的初始化逻辑
  4. 支持多态:客户端通过抽象接口操作对象
  5. 便于单元测试:可以轻松创建mock对象进行测试

⚠️ 缺点:

  1. 增加代码复杂度:引入额外的类和接口
  2. 需要额外设计:需要提前规划产品层次结构
  3. 可能违反开闭原则:简单工厂模式添加新产品需要修改工厂类

五、Qt中使用工厂模式的最佳实践

  1. 内存管理

    cpp 复制代码
    // 使用QObject的父子关系自动管理内存
    QPushButton* createButton(QWidget* parent) {
        return new QPushButton("Button", parent);
    }
    
    // 或者使用智能指针
    std::unique_ptr<Document> createDocument() {
        return std::make_unique<TextDocument>();
    }
  2. 注册机制

    cpp 复制代码
    class DocumentFactory {
    public:
        using CreatorFunc = std::function<Document*()>;
        
        void registerCreator(const QString& type, CreatorFunc creator) {
            creators[type] = creator;
        }
        
        Document* createDocument(const QString& type) {
            if (creators.contains(type))
                return creators[type]();
            return nullptr;
        }
        
    private:
        QMap<QString, CreatorFunc> creators;
    };
    
    // 注册文档类型
    DocumentFactory factory;
    factory.registerCreator("Text", []{ return new TextDocument; });
    factory.registerCreator("Spreadsheet", []{ return new SpreadsheetDocument; });
  3. 与Qt元对象系统结合

    cpp 复制代码
    Document* createDocumentByClassName(const QString& className) {
        int typeId = QMetaType::type(className.toUtf8());
        if (typeId != QMetaType::UnknownType) {
            return static_cast<Document*>(QMetaType::create(typeId));
        }
        return nullptr;
    }

六、何时该使用工厂模式?

工厂模式特别适用于以下场景:

  • 系统需要支持多种类型的对象创建
  • 对象创建过程复杂或需要统一管理
  • 需要解耦对象创建者和使用者
  • 系统需要动态扩展新对象类型
  • 需要为不同环境提供不同实现(如跨平台)

在Qt开发中,工厂模式是构建插件化架构 、实现主题切换 、创建跨平台组件 的利器。当您发现代码中充斥着new操作符和复杂的条件创建语句时,就是引入工厂模式的最佳时机。

相关推荐
两颗泡腾片12 分钟前
黑马程序员C++核心编程笔记--类和对象--运算符重载
c++·笔记
用户6869161349016 分钟前
1999年NOIP普及组旅行家的预算(洛谷P1016):贪心算法实战指南
c++
蝸牛ちゃん44 分钟前
设计模式(十二)结构型:享元模式详解
设计模式·系统架构·软考高级·享元模式
程序员编程指南1 小时前
Qt 与 WebService 交互开发
c语言·开发语言·c++·qt·交互
溟洵1 小时前
Qt 窗口 工具栏QToolBar、状态栏StatusBar
开发语言·前端·数据库·c++·后端·qt
铭哥的编程日记1 小时前
《C++ list 完全指南:list的模拟实现》
c++
程序员编程指南2 小时前
Qt 远程过程调用(RPC)实现方案
c语言·c++·qt·rpc·系统架构
木宇(记得热爱生活)3 小时前
Qt GUI缓存实现
开发语言·qt·缓存
十间fish4 小时前
STL温故知新
c++
西红柿煎蛋4 小时前
C++/const
c++