设计模式
设计模式(Design Patterns)是软件开发人员在软件设计过程中面临的一般问题的解决方案。它们不是直接用来完成工作的代码或“完成品”,而是描述如何组织代码和对象,以及它们之间的交互和职责分配的一种抽象方式。设计模式使得代码更加灵活、可重用、易于理解和维护。
设计模式的六大原则
- 单一职责原则(SRP):一个类负责一项职责。
- 开闭原则(OCP):软件应对扩展开放,对修改关闭。
- 里氏替换原则(LSP):子类可以替换父类且功能不受影响。
- 依赖倒置原则(DIP):高层模块不应依赖低层模块,而应依赖抽象。
- 接口隔离原则(ISP):使用多个小接口比单一大接口好。
- 迪米特法则(LoD):一个类应尽量少地了解其他类。
单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,用于确保一个类仅有一个实例,并提供一个全局访问点来获取这个唯一实例。这种模式在需要控制资源访问,如数据库连接、文件句柄或者需要确保配置信息的全局唯一性等场景下非常有用。
在C++中,单例模式(Singleton Pattern)是一种确保一个类仅有一个实例,并提供一个全局访问点来获取该实例的设计模式。以下是C++中实现单例模式的几种方式:
饿汉式(Eager Initialization)
饿汉式单例模式在类加载时就完成了实例的初始化,因此它是线程安全的,但可能会导致资源浪费,因为实例在程序启动时就已经创建,即使它可能从未被使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Singleton { public: static Singleton* GetInstance() { return &_slt; }
private: Singleton() {} static Singleton _slt;
Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
Singleton Singleton::_slt;
|
懒汉式(Lazy Initialization,线程不安全)
懒汉式单例模式在需要时才创建实例,但如果不加锁,它在多线程环境下可能会创建多个实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Singleton { public: static Singleton* GetInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; }
private: Singleton() {} static Singleton* instance;
Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
Singleton* Singleton::instance = nullptr;
|
注意:上述代码在多线程环境下是不安全的。
懒汉式(Lazy Initialization,线程安全)
为了在多线程环境下保证懒汉式单例模式的线程安全,可以在GetInstance()方法中添加锁。但这种方式可能会影响性能,因为每次调用GetInstance()都需要加锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <mutex>
class Singleton { public: static Singleton* GetInstance() { std::lock_guard<std::mutex> lock(mtx); if (instance == nullptr) { instance = new Singleton(); } return instance; }
private: Singleton() {} static Singleton* instance; static std::mutex mtx;
Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
Singleton* Singleton::instance = nullptr; std::mutex Singleton::mtx;
|
局部静态变量(C++11及更高版本)
C++11引入了局部静态变量的线程安全初始化,这使得实现单例模式变得更加简单和高效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Singleton { public: static Singleton& GetInstance() { static Singleton instance; return instance; }
private: Singleton() {}
Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; };
|
这种方法利用了C++11中的“Magic Static”特性,即在多线程环境下,局部静态变量的初始化是线程安全的。因此,这种方法既简单又高效,是推荐使用的实现方式。
工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需在代码中显式指定所要创建的具体类。工厂模式主要用于创建具有共同接口的对象,但又不希望客户端依赖于这些对象的具体类。工厂模式可以细分为简单工厂模式、工厂方法模式和抽象工厂模式。
简单工厂模式(Simple Factory Pattern)
简单工厂模式又称为静态工厂方法模式,它由一个工厂类根据传入的参数决定创建哪一种类的实例。这种模式通常包括三个角色:工厂类角色、抽象产品角色和具体产品角色。
实现示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <iostream> #include <string> #include <memory>
class Product { public: virtual void use() = 0; virtual ~Product() {} };
class ConcreteProductA : public Product { public: void use() override { std::cout << "Using ConcreteProductA" << std::endl; } };
class ConcreteProductB : public Product { public: void use() override { std::cout << "Using ConcreteProductB" << std::endl; } };
class ProductFactory { public: static std::unique_ptr<Product> createProduct(const std::string& type) { if (type == "A") { return std::make_unique<ConcreteProductA>(); } else if (type == "B") { return std::make_unique<ConcreteProductB>(); } return nullptr; } }; int main() { auto productA = ProductFactory::createProduct("A"); if (productA) { productA->use(); } auto productB = ProductFactory::createProduct("B"); if (productB) { productB->use(); } return 0; }
|
工厂方法模式(Factory Method Pattern)
工厂方法模式定义一个用于创建对象的接口,但让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。
实现示例(基于上面的示例稍作修改):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class ProductFactory { public: virtual std::unique_ptr<Product> createProduct() = 0; virtual ~ProductFactory() {} };
class ConcreteFactoryA : public ProductFactory { public: std::unique_ptr<Product> createProduct() override { return std::make_unique<ConcreteProductA>(); } };
class ConcreteFactoryB : public ProductFactory { public: std::unique_ptr<Product> createProduct() override { return std::make_unique<ConcreteProductB>(); } };
int main() { std::unique_ptr<ProductFactory> factoryA = std::make_unique<ConcreteFactoryA>(); auto productA = factoryA->createProduct(); productA->use(); std::unique_ptr<ProductFactory> factoryB = std::make_unique<ConcreteFactoryB>(); auto productB = factoryB->createProduct(); productB->use(); return 0; }
|
抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。它允许客户端使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。由于它涉及到多个产品族,因此结构相对复杂。
假设我们有两个产品族:一个是汽车制造(包括跑车和SUV),另一个是手机制造(包括智能手机和平板电脑)。每个产品族内部的产品都是相互关联的,并且每个产品族都有其独特的实现方式。
首先,我们定义抽象产品和抽象工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Vehicle { public: virtual void display() = 0; virtual ~Vehicle() {} };
class Phone { public: virtual void call() = 0; virtual ~Phone() {} };
class ProductFactory { public: virtual Vehicle* createVehicle() = 0; virtual Phone* createPhone() = 0; virtual ~ProductFactory() {} };
|
接下来,我们为汽车制造和手机制造分别定义具体的产品和工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class SportsCar : public Vehicle { public: void display() override { std::cout << "Producing a Sports Car\n"; } };
class SUV : public Vehicle { public: void display() override { std::cout << "Producing an SUV\n"; } };
class SmartPhone : public Phone { public: void call() override { std::cout << "Calling with a Smart Phone\n"; } };
class Tablet : public Phone { public: void call() override { std::cout << "Calling (or video calling) with a Tablet\n"; } };
class CarFactory : public ProductFactory { public: Vehicle* createVehicle() override { return new SUV(); }
Phone* createPhone() override { return nullptr; } };
class PhoneFactory : public ProductFactory { public: Vehicle* createVehicle() override { return nullptr; }
Phone* createPhone() override { return new SmartPhone(); } };
|
请注意,在这个例子中,CarFactory 和 PhoneFactory 实际上并不是完整的抽象工厂实现,因为它们只生产各自领域内的产品。在更复杂的场景中,你可能会希望有一个能够同时生产汽车和手机的工厂(尽管这在现实中可能不太常见)。但为了演示目的,我们保持这两个工厂是独立的。
现在,让我们看看如何使用这些工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int main() { ProductFactory* carFactory = new CarFactory(); Vehicle* myCar = carFactory->createVehicle(); myCar->display();
ProductFactory* phoneFactory = new PhoneFactory(); Phone* myPhone = phoneFactory->createPhone(); myPhone->call();
delete myCar; delete myPhone; delete carFactory; delete phoneFactory;
return 0; }
|
这个例子展示了如何在C++中使用抽象工厂模式来创建一系列相关的对象。每个工厂负责生产其特定领域内的产品。客户端代码通过工厂接口与工厂交互,而不需要知道具体的产品实现细节。
观察者模式
观察者模式(Observer Pattern)是一种行为设计模式,用于建立一种对象之间的一对多依赖关系,使得每当一个对象状态发生改变时,其所有依赖者都会得到通知并自动更新。这种模式提供了一种对象设计,让主题(subject)和观察者(observer)之间松耦合,这样它们就可以交互而不需要知道彼此的具体实现细节。
观察者模式的主要角色:
-
Subject(主题):
- 抽象主题:定义一个接口,可以增加、删除和通知观察者。
- 具体主题:存储着状态,当状态改变时,向所有观察者发出通知。
-
Observer(观察者):
- 抽象观察者:定义了一个更新接口,使得自身在得到主题的通知时更新自己。
- 具体观察者:实现抽象观察者的更新接口,以便在得到通知时执行具体操作。
实现示例(C++):
下面是一个简单的C++实现示例,其中有一个Subject类和一个Observer接口,以及它们的具体实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include <iostream> #include <vector> #include <string>
class Observer { public: virtual void update(const std::string& message) = 0; virtual ~Observer() {} };
class ConcreteObserver : public Observer { private: std::string name;
public: ConcreteObserver(const std::string& name) : name(name) {}
void update(const std::string& message) override { std::cout << name << " received: " << message << std::endl; } };
class Subject { private: std::vector<Observer*> observers; std::string message;
public: void attach(Observer* observer) { observers.push_back(observer); }
void detach(Observer* observer) { auto it = std::find(observers.begin(), observers.end(), observer); if (it != observers.end()) { observers.erase(it); } }
void notify() { for (auto observer : observers) { observer->update(message); } }
void setMessage(const std::string& message) { this->message = message; notify(); } };
int main() { Subject subject;
ConcreteObserver obs1("Observer 1"); ConcreteObserver obs2("Observer 2");
subject.attach(&obs1); subject.attach(&obs2);
subject.setMessage("Hello, Observers!");
subject.detach(&obs1);
subject.setMessage("Hello again, remaining Observers!");
return 0; }
|
关键点:
- 松耦合:主题和观察者之间通过抽象层进行交互,这使得它们可以独立地改变和复用。
- 广播通信:当主题状态变化时,所有注册的观察者都会收到通知。
- 动态关联:观察者可以在运行时被添加或删除,从而允许系统更灵活地改变行为。