C++设计模式
什么是 C++ 设计模式?
设计模式(Design Patterns) 是对在软件开发过程中反复出现的常见问题的解决方案的总结和概括。它们提供了一种可复用的、通用的设计方法,帮助开发人员解决软件设计中常见的结构性和行为性问题。设计模式并不是具体的代码,而是解决特定问题的一种架构思路或者方案。
C++ 设计模式是指在 C++ 编程中应用的设计模式,涉及如何通过类和对象组织、解耦以及优化代码结构。设计模式帮助开发者有效地管理复杂性、提高代码的可维护性、可复用性和灵活性。
设计模式的用途
设计模式在软件开发中具有以下重要用途:
提高代码复用性: 设计模式通过定义一套标准的解决方案,使得开发者能够将某些常见的设计问题抽象出来,形成通用的设计模板。这样可以减少重复劳动,提高代码的复用性。例如,工厂模式(Factory Pattern)可以帮助我们简化对象创建的过程,避免了每次都要写重复的构造代码。
提高代码的可维护性: 设计模式帮助开发者构建清晰且易于理解的代码结构。它们通常遵循特定的原则和约定(如单一职责原则、开闭原则等),有助于减少代码中的耦合度和复杂性,从而提高代码的可维护性。例如,策略模式(Strategy Pattern)可以让程序在运行时动态改变算法,避免了对原有代码的修改。
解耦和模块化: 设计模式帮助将系统的各个部分解耦,使得不同的模块可以独立修改和扩展。比如,观察者模式(Observer Pattern)允许对象之间松散耦合,一个对象的状态改变时,可以自动通知所有依赖的对象,而不需要直接引用它们。
提高灵活性和扩展性: 设计模式帮助设计更具灵活性和可扩展性的系统。很多设计模式通过面向接口编程和继承、多态等特性来提供扩展点。例如,桥接模式(Bridge Pattern)通过分离抽象和实现,使得二者可以独立扩展。
简化复杂系统的设计: 设计模式通过标准化的方式组织系统,使得开发人员能够更容易理解系统的结构,降低理解和使用的难度。例如,外观模式(Facade Pattern)可以将一个复杂子系统封装成简单的接口,简化客户端的操作。
增强代码的可测试性: 设计模式通常提倡将复杂逻辑分离成独立的模块或类,使得各个模块的功能单一且清晰。这使得代码更容易进行单元测试。例如,命令模式(Command Pattern)可以将请求封装为对象,从而方便进行单元测试和请求的记录。
适应变化: 设计模式帮助程序应对未来的变化,提供灵活的解决方案。在软件开发中,需求变化是不可避免的,设计模式为系统的扩展和修改提供了良好的基础。例如,状态模式(State Pattern)可以根据状态变化动态改变对象的行为,避免了使用大量条件语句的困扰。
设计模式的核心原则
设计模式通常基于一些面向对象设计的基本原则,如:
单一职责原则(Single Responsibility Principle, SRP): 每个类应该只有一个职责,并且该职责应该由类中的所有方法协同完成。
开闭原则(Open/Closed Principle, OCP): 软件实体应该对扩展开放,对修改关闭。也就是说,通过增加新的代码来扩展系统的功能,而不需要修改现有的代码。
里氏替换原则(Liskov Substitution Principle, LSP): 子类应该可以替换父类,且程序的功能不受影响。
依赖倒转原则(Dependency Inversion Principle, DIP): 高层模块不应该依赖低层模块,二者应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。
接口隔离原则(Interface Segregation Principle, ISP): 一个类不应该强迫其实现的接口方法对它不感兴趣的代码进行依赖。
设计模式的分类
设计模式通常分为以下三大类:
创建型模式(Creational Patterns):与对象的创建过程相关,主要解决如何实例化对象的问题,确保对象的创建过程适应变化。
例如:工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、单例模式(Singleton Pattern)等。结构型模式(Structural Patterns):与类和对象的组合结构相关,主要解决如何组合和组织类、对象的问题。
例如:适配器模式(Adapter Pattern)、外观模式(Facade Pattern)、桥接模式(Bridge Pattern)等。行为型模式(Behavioral Patterns):与对象之间的通信和责任分配相关,主要解决如何分配和协调对象之间的责任和交互的问题。
例如:观察者模式(Observer Pattern)、策略模式(Strategy Pattern)、命令模式(Command Pattern)等。
1. 创建型设计模式
创建型设计模式关注如何实例化对象,尤其是在复杂的对象创建过程中。其主要目标是将对象的创建与使用解耦,使系统能够灵活地管理对象的创建过程。
1.1 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于需要集中控制资源的场景,如配置管理、日志管理、线程池等。
- 优点:
控制实例数量,确保全局共享。
延迟初始化,节省资源。 - 缺点:
隐藏了类的依赖关系,可能导致系统的耦合性增加。
在多线程环境下需要特别注意线程安全问题。
class Singleton {
private:
static Singleton* instance;
// 私有构造函数,防止外部实例化
Singleton() {}
public:
static Singleton* getInstance() {
if (!instance) {
instance = new Singleton();
}
return instance;
}
void showMessage() {
std::cout << "Hello, Singleton!" << std::endl;
}
};
// 初始化静态实例
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s1 = Singleton::getInstance();
s1->showMessage(); // 输出:Hello, Singleton!
return 0;
}
1.2 工厂方法模式(Factory Method Pattern)
工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪个类。这样,创建对象的代码被封装在工厂方法内部,客户端不需要直接依赖具体的类。
- 优点:
客户端代码不依赖具体类,而是依赖抽象工厂。
更容易扩展新的产品类。 - 缺点:
增加了类的数量,可能导致系统变得复杂。
class Product {
public:
virtual void doSomething() = 0;
virtual ~Product() = default;
};
class ConcreteProductA : public Product {
public:
void doSomething() override {
std::cout << "Product A doing something!" << std::endl;
}
};
class ConcreteProductB : public Product {
public:
void doSomething() override {
std::cout << "Product B doing something!" << std::endl;
}
};
class Creator {
public:
virtual Product* factoryMethod() = 0;
virtual ~Creator() = default;
};
class ConcreteCreatorA : public Creator {
public:
Product* factoryMethod() override {
return new ConcreteProductA();
}
};
class ConcreteCreatorB : public Creator {
public:
Product* factoryMethod() override {
return new ConcreteProductB();
}
};
int main() {
Creator* creatorA = new ConcreteCreatorA();
Product* productA = creatorA->factoryMethod();
productA->doSomething(); // 输出:Product A doing something!
Creator* creatorB = new ConcreteCreatorB();
Product* productB = creatorB->factoryMethod();
productB->doSomething(); // 输出:Product B doing something!
delete productA;
delete productB;
delete creatorA;
delete creatorB;
return 0;
}
1.3 抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式提供一个接口,用于创建一系列相关或依赖的对象,而无需指定具体的类。常用于产品族的创建,例如,在跨平台应用中根据不同操作系统创建不同的GUI组件。
- 优点:
使得客户端能够在不同的产品族之间进行选择。
避免了依赖具体类的情况。 - 缺点:
增加了系统的复杂性,可能需要管理更多的接口和实现类。
class Button {
public:
virtual void render() = 0;
virtual ~Button() = default;
};
class WinButton : public Button {
public:
void render() override {
std::cout << "Rendering Windows Button" << std::endl;
}
};
class MacButton : public Button {
public:
void render() override {
std::cout << "Rendering Mac Button" << std::endl;
}
};
class GUIFactory {
public:
virtual Button* createButton() = 0;
virtual ~GUIFactory() = default;
};
class WinFactory : public GUIFactory {
public:
Button* createButton() override {
return new WinButton();
}
};
class MacFactory : public GUIFactory {
public:
Button* createButton() override {
return new MacButton();
}
};
int main() {
GUIFactory* factory = new WinFactory();
Button* button = factory->createButton();
button->render(); // 输出:Rendering Windows Button
delete button;
delete factory;
return 0;
}
1.4 建造者模式(Builder Pattern)
建造者模式通过使用多个步骤构建复杂的对象,将对象的构建过程与它的表示分离。这种模式适用于构建具有复杂结构的对象。
- 优点:
分离了对象的构建过程和表示,便于代码的组织。
使得代码更加灵活,易于扩展。 - 缺点:
需要较多的代码来处理对象的创建。
class Product {
public:
void addPart(const std::string& part) {
parts.push_back(part);
}
void show() {
for (const auto& part : parts) {
std::cout << part << std::endl;
}
}
private:
std::vector<std::string> parts;
};
class Builder {
public:
virtual void buildPart1() = 0;
virtual void buildPart2() = 0;
virtual Product* getResult() = 0;
virtual ~Builder() = default;
};
class ConcreteBuilder : public Builder {
private:
Product* product = new Product();
public:
void buildPart1() override {
product->addPart("Part 1");
}
void buildPart2() override {
product->addPart("Part 2");
}
Product* getResult() override {
return product;
}
~ConcreteBuilder() {
delete product;
}
};
int main() {
Builder* builder = new ConcreteBuilder();
builder->buildPart1();
builder->buildPart2();
Product* product = builder->getResult();
product->show(); // 输出:Part 1 Part 2
delete builder;
delete product;
return 0;
}
1.5 原型模式(Prototype Pattern)
原型模式通过复制现有对象来创建新对象。适用于创建大量相似对象的场景,如需要克隆的复杂对象。
- 优点:
通过复制现有实例来创建新对象,避免了重复创建的开销。
可以动态地决定哪些对象可以被克隆。 - 缺点:
对象的克隆过程可能会变得复杂,特别是当对象的内部结构较为复杂时。
class Prototype {
public:
virtual Prototype* clone() = 0;
virtual void show() = 0;
virtual ~Prototype() = default;
};
class ConcretePrototype : public Prototype {
private:
std::string data;
public:
ConcretePrototype(const std::string& d) : data(d) {}
Prototype* clone() override {
return new ConcretePrototype(*this);
}
void show() override {
std::cout << "Data: " << data << std::endl;
}
};
int main() {
ConcretePrototype* original = new ConcretePrototype("Original");
original->show(); // 输出:Data: Original
ConcretePrototype* clone = static_cast<ConcretePrototype*>(original->clone());
clone->show(); // 输出:Data: Original
delete original;
delete clone;
return 0;
}
2. 结构型设计模式
结构型设计模式关注如何将类和对象组合成更大的结构,目的是提高系统的可扩展性和灵活性。
2.1 适配器模式(Adapter Pattern)
适配器模式通过将一个类的接口转换为客户端所期望的接口,解决了接口不兼容的问题。通常用于使不兼容的类可以一起工作。
- 优点:
可以让不兼容的类协同工作,避免修改原有代码。
提供更高的灵活性,能够复用现有的类。 - 缺点:
可能会增加系统的复杂性,尤其是在大量适配器的情况下。
class Target {
public:
virtual void request() = 0;
};
class Adaptee {
public:
void specificRequest() {
std::cout << "Specific request" << std::endl;
}
};
class Adapter : public Target {
private:
Adaptee* adaptee;
public:
Adapter(Adaptee* a) : adaptee(a) {}
void request() override {
adaptee->specificRequest();
}
};
int main() {
Adaptee* adaptee = new Adaptee();
Target* target = new Adapter(adaptee);
target->request(); // 输出:Specific request
delete adaptee;
delete target;
return 0;
}
2.2 装饰器模式(Decorator Pattern)
装饰器模式允许动态地为一个对象添加额外的职责。装饰器模式提供了一种灵活的方式来扩展类的功能,而不需要修改类本身。
- 优点:
可以在运行时动态地改变对象的行为。
避免使用继承来扩展功能,减少了类的数量。 - 缺点:
增加了系统的复杂度,尤其是装饰器层次较深时。
class Component {
public:
virtual void operation() = 0;
virtual ~Component() = default;
};
class ConcreteComponent : public Component {
public:
void operation() override {
std::cout << "ConcreteComponent operation" << std::endl;
}
};
class Decorator : public Component {
protected:
Component* component;
public:
Decorator(Component* c) : component(c) {}
void operation() override {
component->operation();
}
};
class ConcreteDecoratorA : public Decorator {
public:
ConcreteDecoratorA(Component* c) : Decorator(c) {}
void operation() override {
Decorator::operation();
std::cout << "ConcreteDecoratorA additional behavior" << std::endl;
}
};
int main() {
Component* simple = new ConcreteComponent();
Component* decorated = new ConcreteDecoratorA(simple);
decorated->operation();
// 输出:
// ConcreteComponent operation
// ConcreteDecoratorA additional behavior
delete simple;
delete decorated;
return 0;
}
2.3 代理模式(Proxy Pattern)
代理模式通过提供一个代理对象来控制对目标对象的访问。常见的代理类型有虚拟代理、远程代理、保护代理等。
- 优点:
可以延迟对象的创建和操作,节省资源。
代理可以为目标对象添加额外的功能,如权限控制、缓存等。 - 缺点:
增加了系统的复杂度,尤其是涉及多个代理对象时。
class Subject {
public:
virtual void request() = 0;
virtual ~Subject() = default;
};
class RealSubject : public Subject {
public:
void request() override {
std::cout << "RealSubject request" << std::endl;
}
};
class Proxy : public Subject {
private:
RealSubject* realSubject;
public:
Proxy() : realSubject(nullptr) {}
void request() override {
if (!realSubject) {
realSubject = new RealSubject();
}
realSubject->request();
}
~Proxy() {
delete realSubject;
}
};
int main() {
Proxy proxy;
proxy.request(); // 输出:RealSubject request
return 0;
}
2.4 外观模式(Facade Pattern)
外观模式提供一个统一的接口,简化子系统的复杂度。通过外观类,客户端可以不直接接触复杂的子系统,而是通过简单的接口进行操作。
- 优点:
提供简单的接口,简化了子系统的使用。
减少了系统之间的依赖,提高了系统的灵活性。 - 缺点:
如果外观类过于庞大,可能导致系统复杂度增加。
class SubsystemA {
public:
void operationA() {
std::cout << "Subsystem A operation" << std::endl;
}
};
class SubsystemB {
public:
void operationB() {
std::cout << "Subsystem B operation" << std::endl;
}
};
class SubsystemC {
public:
void operationC() {
std::cout << "Subsystem C operation" << std::endl;
}
};
class Facade {
private:
SubsystemA* subsystemA;
SubsystemB* subsystemB;
SubsystemC* subsystemC;
public:
Facade() {
subsystemA = new SubsystemA();
subsystemB = new SubsystemB();
subsystemC = new SubsystemC();
}
void doSomething() {
subsystemA->operationA();
subsystemB->operationB();
subsystemC->operationC();
}
~Facade() {
delete subsystemA;
delete subsystemB;
delete subsystemC;
}
};
int main() {
Facade* facade = new Facade();
facade->doSomething();
delete facade;
return 0;
}
输出
Subsystem A operation
Subsystem B operation
Subsystem C operation
2.5 组合模式(Composite Pattern)
组合模式将对象组合成树形结构,客户可以像处理单个对象一样处理这些对象的集合。通常用于表示树形结构的数据。
- 优点:
客户端可以统一处理单个对象和对象组合。
方便增加新的组件或叶子节点类型。 - 缺点:
组合模式的使用可能会导致过度泛化,增加设计的复杂性。
class Component {
public:
virtual void operation() = 0;
virtual ~Component() = default;
};
class Leaf : public Component {
public:
void operation() override {
std::cout << "Leaf operation" << std::endl;
}
};
class Composite : public Component {
private:
std::vector<Component*> children;
public:
void add(Component* component) {
children.push_back(component);
}
void operation() override {
std::cout << "Composite operation" << std::endl;
for (auto* child : children) {
child->operation();
}
}
~Composite() {
for (auto* child : children) {
delete child;
}
}
};
int main() {
Leaf* leaf1 = new Leaf();
Leaf* leaf2 = new Leaf();
Composite* composite = new Composite();
composite->add(leaf1);
composite->add(leaf2);
composite->operation();
delete composite;
return 0;
}
输出
Composite operation
Leaf operation
Leaf operation
2.6 桥接模式(Bridge Pattern)
桥接模式通过将抽象部分与实现部分分离,使得两者可以独立地变化。通常用于需要在多个平台或环境下运行的系统。
- 优点:
通过桥接来解耦抽象部分和实现部分,提高灵活性。
可以独立地扩展抽象和实现层次。 - 缺点:
增加了系统的复杂性,尤其是在抽象和实现层次较多时。
class Implementor {
public:
virtual void operationImpl() = 0;
virtual ~Implementor() = default;
};
class ConcreteImplementorA : public Implementor {
public:
void operationImpl() override {
std::cout << "ConcreteImplementorA operation" << std::endl;
}
};
class ConcreteImplementorB : public Implementor {
public:
void operationImpl() override {
std::cout << "ConcreteImplementorB operation" << std::endl;
}
};
class Abstraction {
protected:
Implementor* implementor;
public:
Abstraction(Implementor* imp) : implementor(imp) {}
virtual void operation() {
implementor->operationImpl();
}
virtual ~Abstraction() = default;
};
class RefinedAbstraction : public Abstraction {
public:
RefinedAbstraction(Implementor* imp) : Abstraction(imp) {}
void operation() override {
std::cout << "RefinedAbstraction calling: ";
Abstraction::operation();
}
};
int main() {
Implementor* impA = new ConcreteImplementorA();
Abstraction* abstractionA = new RefinedAbstraction(impA);
abstractionA->operation(); // 输出:RefinedAbstraction calling: ConcreteImplementorA operation
Implementor* impB = new ConcreteImplementorB();
Abstraction* abstractionB = new RefinedAbstraction(impB);
abstractionB->operation(); // 输出:RefinedAbstraction calling: ConcreteImplementorB operation
delete impA;
delete impB;
delete abstractionA;
delete abstractionB;
return 0;
}
3. 行为型设计模式
行为型设计模式关注对象之间的交互和责任的分配,旨在提高系统的灵活性和可扩展性。
3.1 策略模式(Strategy Pattern)
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户端。
- 优点:
客户端可以在运行时选择不同的策略。
增加新的策略时无需修改客户端代码。 - 缺点:
需要管理多个策略类。
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() = default;
};
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy A" << std::endl;
}
};
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
std::cout << "Executing Strategy B" << std::endl;
}
};
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* s) : strategy(s) {}
void setStrategy(Strategy* s) {
strategy = s;
}
void executeStrategy() {
strategy->execute();
}
};
int main() {
ConcreteStrategyA strategyA;
ConcreteStrategyB strategyB;
Context context(&strategyA);
context.executeStrategy(); // 输出:Executing Strategy A
context.setStrategy(&strategyB);
context.executeStrategy(); // 输出:Executing Strategy B
return 0;
}
3.2 观察者模式(Observer Pattern)
观察者模式定义了一对多的依赖关系,当一个对象的状态变化时,所有依赖于它的对象都会收到通知并自动更新。常用于事件处理系统、消息通知等场景。
- 优点:
解耦了主题与观察者,便于扩展。
支持广播通信,多个观察者可以同时接收通知。 - 缺点:
可能导致系统中观察者与被观察者之间的依赖关系复杂化。
class Observer {
public:
virtual void update() = 0;
virtual ~Observer() = default;
};
class Subject {
private:
std::vector<Observer*> observers;
public:
void addObserver(Observer* observer) {
observers.push_back(observer);
}
void removeObserver(Observer* observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify() {
for (auto* observer : observers) {
observer->update();
}
}
};
class ConcreteObserver : public Observer {
private:
std::string name;
public:
ConcreteObserver(const std::string& n) : name(n) {}
void update() override {
std::cout << "Observer " << name << " is notified!" << std::endl;
}
};
int main() {
Subject subject;
ConcreteObserver* observer1 = new ConcreteObserver("Observer1");
ConcreteObserver* observer2 = new ConcreteObserver("Observer2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify(); // 输出:Observer Observer1 is notified! Observer Observer2 is notified!
delete observer1;
delete observer2;
return 0;
}
3.3 状态模式(State Pattern)
状态模式允许对象在其内部状态改变时改变它的行为,通常用于对象的行为受其状态控制的场景。
- 优点:
将状态的转换逻辑与对象的其他行为解耦。
易于管理和扩展新的状态。 - 缺点:
增加了类的数量,可能导致状态管理变得复杂。
class State {
public:
virtual void handle() = 0;
virtual ~State() = default;
};
class ConcreteStateA : public State {
public:
void handle() override {
std::cout << "Handling in State A" << std::endl;
}
};
class ConcreteStateB : public State {
public:
void handle() override {
std::cout << "Handling in State B" << std::endl;
}
};
class Context {
private:
State* state;
public:
Context(State* s) : state(s) {}
void setState(State* s) {
state = s;
}
void request() {
state->handle();
}
};
int main() {
State* stateA = new ConcreteStateA();
State* stateB = new ConcreteStateB();
Context* context = new Context(stateA);
context->request(); // 输出:Handling in State A
context->setState(stateB);
context->request(); // 输出:Handling in State B
delete stateA;
delete stateB;
delete context;
return 0;
}
3.4 命令模式(Command Pattern)
命令模式将请求封装为一个对象,使得用户可以通过不同的命令执行相应的操作。这种模式通常用于将请求和执行解耦的场景。
- 优点:
将请求和执行解耦,使得命令可以被传递、排队和撤销。
方便记录请求和操作历史。 - 缺点:
增加了类的数量,系统可能变得复杂。
class Command {
public:
virtual void execute() = 0;
virtual ~Command() = default;
};
class Receiver {
public:
void action() {
std::cout << "Receiver action" << std::endl;
}
};
class ConcreteCommand : public Command {
private:
Receiver* receiver;
public:
ConcreteCommand(Receiver* r) : receiver(r) {}
void execute() override {
receiver->action();
}
};
class Invoker {
private:
Command* command;
public:
void setCommand(Command* cmd) {
command = cmd;
}
void invoke() {
command->execute();
}
};
int main() {
Receiver* receiver = new Receiver();
Command* command = new ConcreteCommand(receiver);
Invoker* invoker = new Invoker();
invoker->setCommand(command);
invoker->invoke(); // 输出:Receiver action
delete command;
delete receiver;
delete invoker;
return 0;
}
3.5 责任链模式(Chain of Responsibility Pattern)
责任链模式通过将请求沿着链传递,直到有对象处理该请求。常用于事件处理和请求分发系统。
- 优点:
请求处理逻辑可以动态地组合和扩展。
可以减少多个条件判断语
class Handler {
protected:
Handler* nextHandler;
public:
Handler() : nextHandler(nullptr) {}
virtual void handleRequest() = 0;
void setNext(Handler* next) {
nextHandler = next;
}
virtual ~Handler() = default;
};
class ConcreteHandlerA : public Handler {
public:
void handleRequest() override {
std::cout << "Handler A is handling request" << std::endl;
if (nextHandler) nextHandler->handleRequest();
}
};
class ConcreteHandlerB : public Handler {
public:
void handleRequest() override {
std::cout << "Handler B is handling request" << std::endl;
if (nextHandler) nextHandler->handleRequest();
}
};
int main() {
Handler* handlerA = new ConcreteHandlerA();
Handler* handlerB = new ConcreteHandlerB();
handlerA->setNext(handlerB);
handlerA->handleRequest();
delete handlerA;
delete handlerB;
return 0;
}
输出
Handler A is handling request
Handler B is handling request