C++设计模式:何时使用与为何使用
你是否曾经反复重写代码,因为新功能破坏了旧的架构?或者花费数小时调试,试图弄清楚是谁以及为什么修改了全局变量?听起来很熟悉?那么欢迎来到设计模式的世界。
设计模式并非万能灵药。它们是经过实战检验的、用于解决典型问题的方案。它们不会让你的代码变得完美,但能帮助你与其他开发者使用同一种语言交流,并避免成千上万的程序员在你之前已经踩过的坑。
在本文中,我们将探讨C++中的三大类模式:创建型、结构型和行为型。了解何时应该使用它们,以及何时最好绕开它们。开始吧!
创建型模式:控制对象的创建
创建型模式负责灵活地创建对象。它们隐藏了实例化的逻辑,使系统独立于其组件的具体创建方式。
单例模式 (Singleton)
经典模式。确保一个类只有一个实例,并提供一个全局访问点。听起来很诱人,但请明智地使用它——如果膨胀到“上帝对象”的程度,单例模式往往会变成反模式。
何时使用:日志记录器、配置管理器、线程池、硬件接口。
C++示例(线程安全,C++11及更高版本):
class Logger {public: static Logger& getInstance() { static Logger instance; // 仅初始化一次,即使在多线程环境下 return instance; }
void log(const std::string& msg) { std::cout << "[LOG]: " << msg << std::endl; }
// 禁止拷贝和赋值 Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete;
private: Logger() = default; // 私有构造函数 ~Logger() = default;};
// 使用Logger::getInstance().log("系统已启动");工厂方法模式 (Factory Method)
定义一个创建对象的接口,但让子类决定实例化哪个类。当你事先不知道需要哪个具体类时,它非常适用。
何时使用:解析不同格式(JSON、XML、YAML)、为不同操作系统创建UI元素、与不同数据库交互。
示例:
// 抽象产品class Document {public: virtual void open() = 0; virtual ~Document() = default;};
// 具体产品class PDFDocument : public Document { void open() override { std::cout << "打开PDF" << std::endl; }};
class WordDocument : public Document { void open() override { std::cout << "打开Word" << std::endl; }};
// 工厂class Application {public: virtual Document* createDocument() = 0; // 工厂方法 virtual ~Application() = default;
void newDocument() { Document* doc = createDocument(); doc->open(); delete doc; // 实际代码中应使用智能指针 }};
class PDFApp : public Application { Document* createDocument() override { return new PDFDocument(); }};
// 使用PDFApp app;app.newDocument(); // 打开PDF结构型模式:组装积木
这些模式有助于将类和对象组织成更大的结构,同时保持灵活性和效率。
适配器模式 (Adapter)
允许接口不兼容的对象协同工作。想象一下,你有一个用于处理XML的旧库,而新模块需要JSON。适配器就是你的救星。
何时使用: