23种设计模式_Modern C++
设计原则:
单一职责原则(SRP):一个类应该仅有一个引起它变化的原因;变化的方向隐含着类的责任。
开放封闭原则(OCP):对扩展开放,对更改封闭;类模块应该是可扩展的,但是不可修改。
里氏替换原则(LSP):子类必须能够替换它们的基类(IS - A);继承表达类型抽象。
接口隔离原则(ISP):不应该强迫客户程序依赖它们不用的方法;接口应该小而完备。
依赖倒置原则(DIP):高层模块不应该依赖于低层模块,二者应该依赖于抽象;抽象不应该依赖于实现细节,实现细节依赖于抽象。
优先使用对象组合而不是继承:子类父类耦合度高,在一定程度上破坏了封装性。
面向接口编程:减少系统中各部分的依赖关系,实现”高内聚,松耦合“的设计方案。
封装变化点:让设计者在一层进行修改,而不影响其它层次的代码。实现层次间的松耦合。
创建型模式 (Creational Patterns):
1. 单例模式 (Singleton)
-
GOF定义:
- 确保一个类只有一个实例,并提供一个全局访问点。
-
动机:
- 保证一个类只有一个实例并且这个实例易于被访问。
-
类图
- 时序图
- 代码
#include <iostream>
class Singleton {
private:
// 私有构造函数,防止外部直接创建对象
Singleton() {
}
public:
// 删除拷贝构造函数和赋值操作符,防止复制实例
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 公有静态方法,用于获取类的唯一实例
static Singleton* getInstance() {
static Singleton instance;
return &instance;
}
// 示例方法,用于展示单例的功能
void doSomething() {
std::cout << "Doing something..." << std::endl;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
// 客户端代码
int main() {
// 获取单例对象并调用方法
Singleton* singleton = Singleton::getInstance();
singleton->doSomething();
return 0;
}
2. 工厂方法模式 (Factory Method)
-
GOF定义:
- 定义一个用于创建对象的接口,让子类决定实例化哪一个类。
-
动机:
- 在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
- 如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?
-
类图
- 时序图
- 代码
#include <iostream>
#include <memory>
// 抽象产品类
class Product {
public:
virtual ~Product() {
}
virtual std::string Use() const = 0;
};
// 具体产品类A
class ConcreteProductA : public Product {
public:
std::string Use() const override {
return "使用产品A";
}
};
// 具体产品类B
class ConcreteProductB : public Product {
public:
std::string Use() const override {
return "使用产品B";
}
};
// 抽象工厂类
class Creator {
public:
virtual ~Creator() {
}
virtual std::unique_ptr<Product> FactoryMethod() const = 0;
};
// 具体工厂类A
class ConcreteCreatorA : public Creator {
public:
std::unique_ptr<Product> FactoryMethod() const override {
return std::make_unique<ConcreteProductA>();
}
};
// 具体工厂类B
class ConcreteCreatorB : public Creator {
public:
std::unique_ptr<Product> FactoryMethod() const override {
return std::make_unique<ConcreteProductB>();
}
};
// 客户端代码
void ClientCode(const Creator& creator) {
auto product = creator.FactoryMethod();
std::cout << product->Use() << std::endl;
}
int main() {
ConcreteCreatorA creatorA;
ClientCode(creatorA);
ConcreteCreatorB creatorB;
ClientCode(creatorB);
}
3. 抽象工厂模式 (Abstract Factory)
-
GOF定义:
- 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
-
动机:
- 为了更清晰地理解工厂方法模式,需要先引入两个概念:
- 产品等级结构 :产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
- 产品族 :在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
- 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
- 为了更清晰地理解工厂方法模式,需要先引入两个概念:
-
类图
- 时序图
- 代码
#include <iostream>
#include <memory>
// 抽象产品A和B
class AbstractProductA {
public:
virtual ~AbstractProductA() {
}
virtual std::string UsefulFunctionA() const = 0;
};
class AbstractProductB {
public:
virtual ~AbstractProductB() {
}
virtual std::string UsefulFunctionB() const = 0;
};
// 具体产品A1和A2
class ConcreteProductA1 : public AbstractProductA {
public:
std::string UsefulFunctionA() const override {
return "The result of the product A1.";
}
};
class ConcreteProductA2 : public AbstractProductA {
public:
std::string UsefulFunctionA() const override {
return "The result of the product A2.";
}
};
// 具体产品B1和B2
class ConcreteProductB1 : public AbstractProductB {
public:
std::string UsefulFunctionB() const override {
return "The result of the product B1.";
}
};
class ConcreteProductB2 : public AbstractProductB {
public:
std::string UsefulFunctionB() const override {
return "The result of the product B2.";
}
};
// 抽象工厂
class AbstractFactory {
public:
virtual ~AbstractFactory() {
}
virtual std::unique_ptr<AbstractProductA> CreateProductA() const = 0;
virtual std::unique_ptr<AbstractProductB> CreateProductB() const = 0;
};
// 具体工厂1和2
class ConcreteFactory1 : public AbstractFactory {
public:
std::unique_ptr<AbstractProductA> CreateProductA() const override {
return std::make_unique<ConcreteProductA1>();
}
std::unique_ptr<AbstractProductB> CreateProductB() const override {
return std::make_unique<ConcreteProductB1>();
}
};
class ConcreteFactory2 : public AbstractFactory {
public:
std::unique_ptr<AbstractProductA> CreateProductA() const override {
return std::make_unique<ConcreteProductA2>();
}
std::unique_ptr<AbstractProductB> CreateProductB() const override {
return std::make_unique<ConcreteProductB2>();
}
};
// 客户端代码
void ClientCode(const AbstractFactory &factory) {
auto productA = factory.CreateProductA();
auto productB = factory.CreateProductB();
std::cout << productA->UsefulFunctionA() << std::endl;
std::cout << productB->UsefulFunctionB() << std::endl;
}
int main() {
std::cout << "Client: Testing client code with the first factory type:\n";
ConcreteFactory1 factory1;
ClientCode(factory1);
std::cout << "\nClient: Testing the same client code with the second factory type:\n";
ConcreteFactory2 factory2;
ClientCode(factory2);
}
4. 建造者模式 (Builder)
-
GOF定义:
- 将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
-
动机:
- 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这 个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
-
类图
- 时序图
- 代码
#include <iostream>
#include <string>
// 产品类
class Product {
public:
// 一系列用于添加部件的方法
void AddPart(const std::string& part) {
parts_.push_back(part);
}
void ShowProduct() const {
std::cout << "Product parts: ";
for (const auto& part : parts_) {
std::cout << part << ", ";
}
std::cout << "\b\b " << std::endl; // 删除最后的逗号和空格
}
private:
std::vector<std::string> parts_;
};
// 抽象建造者类
class Builder {
public:
virtual ~Builder() {
}
virtual void BuildPartA() const = 0;
virtual void BuildPartB() const = 0;
virtual void BuildPartC() const = 0;
virtual Product* GetProduct() = 0;
};
// 具体建造者类
class ConcreteBuilder : public Builder {
public:
ConcreteBuilder() {
Reset();
}
~ConcreteBuilder() {
delete product_;
}
void Reset() {
if (product_ != nullptr) {
delete product_;
}
product_ = new Product();
}
void BuildPartA() const override {
product_->AddPart("PartA");
}
void BuildPartB() const override {
product_->AddPart("PartB");
}
void BuildPartC() const override {
product_->AddPart("PartC");
}
Product* GetProduct() override {
Product* result = product_;
Reset();
return result;
}
private:
Product* product_;
};
// 指挥者类
class Director {
public:
void SetBuilder(Builder* builder) {
builder_ = builder;
}
// 构建最小特征的产品
void BuildMinimalViableProduct() {
builder_->BuildPartA();
}
// 构建完整特征的产品
void BuildFullFeaturedProduct() {
builder_->BuildPartA();
builder_->BuildPartB();
builder_->BuildPartC();
}
private:
Builder* builder_;
};
// 客户端代码
int main() {
Director* director = new Director();
ConcreteBuilder* builder = new ConcreteBuilder();
director->SetBuilder(builder);
// 构建最小特征的产品
std::cout << "Standard basic product:" << std::endl;
director->BuildMinimalViableProduct();
Product* p = builder->GetProduct();
p->ShowProduct();
delete p;
// 构建完整特征的产品
std::cout << "Standard full featured product:" << std::endl;
director->BuildFullFeaturedProduct();
p = builder->GetProduct();
p->ShowProduct();
delete p;
delete director;
delete builder;
return 0;
}
5. 原型模式 (Prototype)
-
GOF定义:
- 使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
-
动机:
- 在软件系统中,经常面临这“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
- 如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”,从而使得依赖这些”易变对象“的客户程序不随着需求改变而改变。
-
类图
- 代码
#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>
// “Prototype”基类
class Prototype {
public:
virtual ~Prototype() {
}
virtual std::unique_ptr<Prototype> clone() const = 0;
virtual void execute() const = 0;
};
// 具体的原型类
class ConcretePrototypeA : public Prototype {
private:
std::string exampleState;
public:
ConcretePrototypeA(const std::string& state) : exampleState(state) {
}
std::unique_ptr<Prototype> clone() const override {
return std::make_unique<ConcretePrototypeA>(*this);
}
void execute() const override {
std::cout << "ConcretePrototypeA state: " << exampleState << std::endl;
}
};
// 另一个具体的原型类