工程实践中常见的几种设计模式解析及 C++ 实现
工程实践中常见的几种设计模式解析及 C++ 实现
在软件工程中,设计模式是一种通用的解决方案,用于解决常见问题和优化代码结构。它们通过提供一种规范化的编程思想,帮助开发者写出更高效、可维护和可扩展的代码。本文将介绍几种在工程实践中常见的设计模式,包括其实现原理、使用场景以及注意事项,并结合 C++ 语言进行实现。
1. 单例模式 (Singleton Pattern)
实现原理
单例模式确保一个类只有一个实例,并提供全局访问点。其核心思想是通过控制构造函数和复制操作符,使得类只能生成一个对象实例。
关键点:
- 隐藏构造函数(将构造函数设为私有)。
- 提供一个静态方法用于获取唯一实例。
- 使用懒汉式或饿汉式实现线程安全的单例模式。
使用场景
- 当需要全局只有一个实例时,例如配置管理、日志记录等。
- 需要避免大量重复对象创建的情况。
注意事项
- 单例模式可能会隐藏类之间的依赖关系,导致代码难以维护。
- 线程安全性需要额外处理(如双重检查锁定)。
- 在某些场景下,单例模式可能导致性能问题或内存泄漏。
C++ 实现
class Singleton {
private:
static Singleton* instance;
Singleton() = default; // 隐藏构造函数
~Singleton() = default; // 隐藏析构函数
public:
// 静态方法获取实例(线程安全)
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
// 删除复制操作符,防止复制
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
void doSomething() {
// 业务逻辑
}
};
// 静态变量初始化为 nullptr
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if (s1 == s2) { // 比较两个指针是否相同
// 输出:两者指向同一个实例
}
return 0;
}
2. 工厂模式 (Factory Pattern)
实现原理
工厂模式通过提供一个接口,用于创建对象,而无需显式指定具体类。这提高了代码的灵活性和可扩展性。
关键点:
- 定义一个抽象产品类(Product)。
- 提供一个工厂类(Factory),通过其方法创建具体的子类实例。
- 工厂模式分为简单工厂模式和抽象工厂模式。
使用场景
- 需要根据不同的条件动态选择具体实现时。
- 避免代码直接依赖于具体实现类,提高系统的灵活性。
注意事项
- 工厂类可能会变得复杂,尤其是在支持多种产品的情况下。
- 增加新的产品类需要同时修改工厂类,这可能违反“开闭原则”。
C++ 实现
// 抽象产品类
class Product {
public:
virtual ~Product() = default;
virtual void use() = 0;
};
// 具体产品类
class ConcreteProductA : public Product {
public:
void use() override {
// 使用具体实现 A
}
};
class ConcreteProductB : public Product {
public:
void use() override {
// 使用具体实现 B
}
};
// 工厂类
class Factory {
public:
virtual ~Factory() = default;
virtual std::unique_ptr<Product> createProduct() = 0;
};
// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:
std::unique_ptr<Product> createProduct() override {
return std::make_unique<ConcreteProductA>();
}
};
// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:
std::unique_ptr<Product> createProduct() override {
return std::make_unique<ConcreteProductB>();
}
};
int main() {
// 使用工厂创建产品
Factory* factory = new ConcreteFactoryA();
auto product = factory->createProduct();
product->use();
delete factory;
return 0;
}
3. 观察者模式 (Observer Pattern)
实现原理
观察者模式定义了一种一对多的依赖关系,当一个对象(主题)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。
关键点:
- 定义一个主题类(Subject),包含状态和注册/注销观察者的接口。
- 观察者类(Observer)通过继承或实现接口,提供一个更新方法。
- 主题类维护一个观察者列表,并在状态变化时通知所有观察者。
使用场景
- 系统中存在一对多的依赖关系时。
- 需要动态地添加或删除观察者。
注意事项
- 观察者模式可能会导致循环依赖问题。
- 观察者和主题之间的耦合可能会影响代码的可维护性。
C++ 实现
#include <vector>
#include <memory>
class Observer {
public:
virtual ~Observer() = default;
virtual void update(int value) = 0;
};
class Subject {
private:
int state_;
std::vector<std::shared_ptr<Observer>> observers_;
public:
void attach(std::shared_ptr<Observer> observer) {
observers_.push_back(observer);
}
void detach(std::shared_ptr<Observer> observer) {
// 实现观察者的移除逻辑
}
int getState() const {
return state_;
}
void setState(int value) {
if (state_ != value) {
state_ = value;
notify();
}
}
private:
void notify() {
for (auto& observer : observers_) {
observer->update(state_);
}
}
};
class ConcreteObserver : public Observer {
public:
void update(int value) override {
// 处理状态变化
}
};
int main() {
std::shared_ptr<Subject> subject = std::make_shared<Subject>();
std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>();
std::shared_ptr<ConcreteObserver> observer2 = std::make_shared<ConcreteObserver>();
subject->attach(observer1);
subject->attach(observer2);
subject->setState(10); // 所有观察者都会收到更新
return 0;
}
4. 策略模式 (Strategy Pattern)
实现原理
策略模式定义了一系列算法,并将它们封装起来,使它们可以互换。上下文类通过接口调用具体策略类的方法。
关键点:
- 定义一个策略接口(Strategy),包含算法的声明。
- 具体策略类(Concrete Strategy)实现策略接口。
- 上下文类(Context)维护一个策略对象,并根据需要切换策略。
使用场景
- 需要动态选择不同算法时。
- 系统中存在多个相似但具体的算法,且希望它们可以互换使用。
注意事项
- 增加新的具体策略类可能会影响上下文的代码复杂性。
- 必须确保所有策略接口的一致性。
C++ 实现
class Strategy {
public:
virtual ~Strategy() = default;
virtual int calculate(int a, int b) = 0;
};
// 具体策略类 A:加法
class AddStrategy : public Strategy {
public:
int calculate(int a, int b) override {
return a + b;
}
};
// 具体策略类 B:乘法
class MultiplyStrategy : public Strategy {
public:
int calculate(int a, int b) override {
return a * b;
}
};
// 上下文类
class Context {
private:
std::shared_ptr<Strategy> strategy_;
public:
Context(std::shared_ptr<Strategy> strategy) : strategy_(strategy) {}
void setStrategy(std::shared_ptr<Strategy> strategy) {
strategy_ = strategy;
}
int execute(int a, int b) {
return strategy_->calculate(a, b);
}
};
int main() {
std::shared_ptr<Context> context = std::make_shared<Context>(std::make_shared<AddStrategy>());
// 使用加法策略
int result1 = context->execute(3, 5); // 8
// 切换到乘法策略
context->setStrategy(std::make_shared<MultiplyStrategy>());
int result2 = context->execute(3, 5); // 15
return 0;
}
总结
以上四种设计模式(单例模式、工厂模式、观察者模式和策略模式)是工程实践中最常用的设计模式之一。每种模式都有其适用的场景和注意事项,合理使用它们可以显著提升代码的质量和系统的可维护性。
在实际开发中,我们需要根据具体需求选择合适的设计模式,并结合语言特性和框架进行实现。同时,也要注意避免过度设计,以免增加不必要的复杂性。