C++中常用的设计模式有很多,设计模式是解决常见问题的经过验证的最佳实践。以下是一些常用的设计模式:
这些设计模式都有特定的应用场景,可以根据问题的性质选择合适的设计模式来解决。设计模式有助于提高代码的可维护性、可扩展性和复用性。
命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而允许你参数化不同的请求、将请求排队、记录请求日志,或者支持可撤销的操作。命令模式的核心思想是将请求的发送者与请求的接收者解耦。
命令模式包含以下几个主要角色:
execute
。具体的命令类将实现这个接口,将请求参数绑定到接收者,并在 execute
方法中执行具体的操作。命令模式的主要优点包括:
以下是一个简单的命令模式的 C++ 示例:
#include
// 命令接口
class Command {
public:
virtual void execute() = 0;
};
// 具体命令
class LightOnCommand : public Command {
public:
LightOnCommand(Light& light) : light_(light) {}
void execute() override {
light_.on();
}
private:
Light& light_;
};
// 接收者
class Light {
public:
void on() {
std::cout << "Light is on" << std::endl;
}
void off() {
std::cout << "Light is off" << std::endl;
}
};
// 调用者
class RemoteControl {
public:
void setCommand(Command* command) {
command_ = command;
}
void pressButton() {
command_->execute();
}
private:
Command* command_;
};
int main() {
Light livingRoomLight;
LightOnCommand livingRoomLightOn(livingRoomLight);
RemoteControl remote;
remote.setCommand(&livingRoomLightOn);
remote.pressButton();
return 0;
}
在这个示例中,我们有一个命令接口 Command
,定义了 execute
方法。具体命令 LightOnCommand
包含一个接收者对象 Light
,在 execute
方法中调用接收者的方法。
调用者 RemoteControl
通过设置具体命令对象,并调用 pressButton
方法来执行命令。这种方式实现了调用者和接收者的解耦,调用者只需要知道如何发送命令,而不需要知道命令是如何执行的。
命令模式非常适用于构建可扩展和可维护的系统,特别是需要支持撤销、重做和构建复杂命令序列的情况。
状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态改变时改变其行为。状态模式的核心思想是将不同状态抽象为独立的状态类,使对象能够在运行时切换不同状态,而不需要修改其代码。
状态模式包含以下几个主要角色:
状态模式的主要优点包括:
以下是一个简单的状态模式的 C++ 示例:
#include
// 状态接口
class State {
public:
virtual void handle() = 0;
};
// 具体状态 A
class ConcreteStateA : public State {
public:
void handle() override {
std::cout << "Handling state A" << std::endl;
}
};
// 具体状态 B
class ConcreteStateB : public State {
public:
void handle() override {
std::cout << "Handling state B" << std::endl;
}
};
// 上下文
class Context {
public:
void setState(State* state) {
state_ = state;
}
void request() {
state_->handle();
}
private:
State* state_;
};
int main() {
ConcreteStateA stateA;
ConcreteStateB stateB;
Context context;
context.setState(&stateA);
context.request();
context.setState(&stateB);
context.request();
return 0;
}
在这个示例中,我们有一个状态接口 State
,定义了 handle
方法,具体状态类 ConcreteStateA
和 ConcreteStateB
分别实现了这个接口。
上下的 Context
包含一个状态对象的引用,它可以在运行时切换不同的状态。当调用 request
方法时,上下文对象会委托给当前状态对象来执行特定的行为。
状态模式使对象能够根据内部状态的改变而改变行为,这有助于消除大量的条件分支,提高了代码的可维护性和可扩展性。状态模式常用于处理对象的状态机、有限状态机、工作流等场景。
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一组算法的骨架,将一些步骤延迟到子类实现。模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
模板方法模式包含以下几个主要角色:
模板方法模式的主要特点包括:
以下是一个简单的模板方法模式的 C++ 示例:
#include
// 模板方法
class AbstractClass {
public:
// 模板方法定义了算法的骨架,包括一组步骤
void templateMethod() {
step1();
step2();
step3();
}
// 具体步骤由子类实现
virtual void step1() = 0;
virtual void step2() = 0;
virtual void step3() = 0;
};
// 具体模板
class ConcreteClassA : public AbstractClass {
public:
void step1() override {
std::cout << "ConcreteClassA - Step 1" << std::endl;
}
void step2() override {
std::cout << "ConcreteClassA - Step 2" << std::endl;
}
void step3() override {
std::cout << "ConcreteClassA - Step 3" << std::endl;
}
};
class ConcreteClassB : public AbstractClass {
public:
void step1() override {
std::cout << "ConcreteClassB - Step 1" << std::endl;
}
void step2() override {
std::cout << "ConcreteClassB - Step 2" << std::endl;
}
void step3() override {
std::cout << "ConcreteClassB - Step 3" << std::endl;
}
};
int main() {
ConcreteClassA a;
ConcreteClassB b;
a.templateMethod();
b.templateMethod();
return 0;
}
在这个示例中,我们有一个抽象类 AbstractClass
,它定义了一个模板方法 templateMethod
,包括一组步骤(step1
、step2
、step3
)。具体的步骤由子类实现。具体子类 ConcreteClassA
和 ConcreteClassB
分别实现了这些步骤。
当我们调用 templateMethod
时,模板方法会按照定义的算法骨架执行各个步骤。不同的子类可以重新定义这些步骤,以满足其特定需求。
模板方法模式非常适用于需要定义算法骨架但允许某些步骤由子类自定义的情况,例如,创建框架、工作流程或其他多步骤的操作。这有助于提高代码的可复用性和可维护性。
访问者模式(Visitor Pattern)是一种行为型设计模式,它用于分离数据结构和数据操作,并允许在不修改数据结构的情况下添加新的操作。访问者模式的核心思想是将数据结构和操作分离,使得数据结构可以在不同的操作下表现不同的行为。
访问者模式包含以下几个主要角色:
accept
方法,该方法接受一个访问者对象作为参数,允许访问者访问该元素。accept
方法,用于调用访问者的相应操作。访问者模式的主要优点包括:
以下是一个简单的访问者模式的 C++ 示例:
#include
#include
// 前向声明,让元素类知道访问者类
class Visitor;
// 元素接口
class Element {
public:
virtual void accept(Visitor& visitor) = 0;
};
// 具体元素 A
class ConcreteElementA : public Element {
public:
void accept(Visitor& visitor) override {
visitor.visitElementA(*this);
}
void operationA() {
std::cout << "Operation A on ConcreteElementA" << std::endl;
}
};
// 具体元素 B
class ConcreteElementB : public Element {
public:
void accept(Visitor& visitor) override {
visitor.visitElementB(*this);
}
void operationB() {
std::cout << "Operation B on ConcreteElementB" << std::endl;
}
};
// 访问者接口
class Visitor {
public:
virtual void visitElementA(ConcreteElementA& element) = 0;
virtual void visitElementB(ConcreteElementB& element) = 0;
};
// 具体访问者
class ConcreteVisitor : public Visitor {
public:
void visitElementA(ConcreteElementA& element) override {
element.operationA();
}
void visitElementB(ConcreteElementB& element) override {
element.operationB();
}
};
int main() {
ConcreteElementA elementA;
ConcreteElementB elementB;
ConcreteVisitor visitor;
elementA.accept(visitor);
elementB.accept(visitor);
return 0;
}
在这个示例中,我们有两种具体元素 ConcreteElementA
和 ConcreteElementB
,它们都实现了元素接口,并提供了 accept
方法,以允许访问者访问这些元素。
具体访问者 ConcreteVisitor
实现了访问者接口中定义的访问操作,其中包括操作 A 和操作 B。
通过访问者模式,我们可以在不修改元素类的情况下,为元素类添加新的操作(在这个示例中是操作 A 和操作 B)。这种分离数据结构和操作的设计模式使得代码更加灵活和可维护。
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树状结构以表示“部分-整体”的层次结构。组合模式允许客户端以一致的方式处理单个对象和对象组合。
组合模式包含以下几个主要角色:
组合模式的主要优点包括:
以下是一个简单的组合模式的 C++ 示例:
#include
#include
// 抽象组件
class Component {
public:
virtual void operation() = 0;
};
// 叶子组件
class Leaf : public Component {
public:
void operation() override {
std::cout << "Leaf operation" << std::endl;
}
};
// 容器组件
class Composite : public Component {
public:
void operation() override {
std::cout << "Composite operation" << std::endl;
// 调用子组件的操作
for (Component* child : children_) {
child->operation();
}
}
void add(Component* component) {
children_.push_back(component);
}
private:
std::vector<Component*> children_;
};
int main() {
Leaf leaf1, leaf2;
Composite composite;
composite.add(&leaf1);
composite.add(&leaf2);
composite.operation();
return 0;
}
在这个示例中,我们有一个抽象组件 Component
,包括一个操作方法 operation
。Leaf
类是叶子组件,它是组件的具体实现,而 Composite
类是容器组件,它可以包含多个子组件。
在 main
函数中,我们创建了两个叶子组件和一个容器组件,并将叶子组件添加到容器组件中。当调用容器组件的 operation
方法时,它会递归调用其子组件的 operation
方法,从而实现了整体-部分的层次结构。
组合模式常用于处理树状结构,例如文件系统、图形界面控件、组织架构等情况,其中可以递归地组合和管理各种对象。
迭代器模式(Iterator Pattern)是一种行为型设计模式,用于提供一种访问聚合对象中各个元素的方法,而无需暴露聚合对象的内部表示。迭代器模式将遍历聚合对象的操作封装在一个迭代器对象中,使客户端能够以一致的方式遍历不同类型的聚合对象。
迭代器模式包含以下几个主要角色:
迭代器模式的主要优点包括:
以下是一个简单的迭代器模式的 C++ 示例:
#include
#include
// 抽象迭代器
class Iterator {
public:
virtual int next() = 0;
virtual bool hasNext() = 0;
};
// 具体迭代器
class ConcreteIterator : public Iterator {
public:
ConcreteIterator(const std::vector<int>& collection) : collection_(collection), index_(0) {}
int next() override {
return collection_[index_++];
}
bool hasNext() override {
return index_ < collection_.size();
}
private:
std::vector<int> collection_;
int index_;
};
// 抽象聚合
class Aggregate {
public:
virtual Iterator* createIterator() = 0;
};
// 具体聚合
class ConcreteAggregate : public Aggregate {
public:
ConcreteAggregate(const std::vector<int>& collection) : collection_(collection) {}
Iterator* createIterator() override {
return new ConcreteIterator(collection_);
}
private:
std::vector<int> collection_;
};
int main() {
std::vector<int> data = {1, 2, 3, 4, 5};
ConcreteAggregate aggregate(data);
Iterator* iterator = aggregate.createIterator();
while (iterator->hasNext()) {
std::cout << iterator->next() << " ";
}
delete iterator;
return 0;
}
在这个示例中,我们有一个抽象迭代器 Iterator
,具体迭代器 ConcreteIterator
,抽象聚合 Aggregate
,以及具体聚合 ConcreteAggregate
。
具体聚合 ConcreteAggregate
包含了一组整数元素,并提供了创建迭代器的方法。具体迭代器 ConcreteIterator
实现了在集合上的遍历操作。
在 main
函数中,我们创建了一个包含整数的聚合对象,然后创建了一个迭代器对象,通过迭代器以一致的方式遍历聚合中的元素。这种设计模式使得客户端可以在不关心聚合内部结构的情况下进行遍历操作。
中介者模式(Mediator Pattern)是一种行为型设计模式,它用于减少对象之间的直接通信,将对象间的交互通过一个中介者对象进行协调和控制。中介者模式有助于降低系统中对象之间的耦合度,使系统更易维护和扩展。
中介者模式包含以下几个主要角色:
中介者模式的主要优点包括:
以下是一个简单的中介者模式的 C++ 示例:
#include
#include
// 抽象中介者
class Mediator {
public:
virtual void sendMessage(const std::string& message, class Colleague* colleague) = 0;
};
// 具体中介者
class ConcreteMediator : public Mediator {
public:
void sendMessage(const std::string& message, class Colleague* colleague) override {
std::cout << "Message from " << colleague->getName() << ": " << message << std::endl;
}
};
// 同事类
class Colleague {
public:
Colleague(const std::string& name, Mediator* mediator) : name_(name), mediator_(mediator) {}
void sendMessage(const std::string& message) {
mediator_->sendMessage(message, this);
}
const std::string& getName() {
return name_;
}
private:
std::string name_;
Mediator* mediator_;
};
int main() {
ConcreteMediator mediator;
Colleague colleague1("Colleague 1", &mediator);
Colleague colleague2("Colleague 2", &mediator);
colleague1.sendMessage("Hello from Colleague 1");
colleague2.sendMessage("Hi from Colleague 2");
return 0;
}
在这个示例中,我们有一个抽象中介者 Mediator
,具体中介者 ConcreteMediator
,以及两个同事类 Colleague
。同事类通过中介者来发送消息,而不直接与其他同事类进行通信。
中介者模式在协调对象之间的交互时非常有用,特别是在大型系统中,当对象之间的交互关系复杂时,可以通过引入中介者来简化和集中控制交互逻辑。这有助于减少系统的复杂性和提高可维护性。
备忘录模式(Memento Pattern)是一种行为型设计模式,它用于捕获一个对象的内部状态,并将其保存在一个外部对象中,从而可以在以后将对象恢复到先前的状态。备忘录模式的关键思想是在不破坏封装性的前提下,将对象的状态保存和恢复。
备忘录模式包含以下几个主要角色:
备忘录模式的主要优点包括:
以下是一个简单的备忘录模式的 C++ 示例:
#include
#include
// 备忘录类
class Memento {
public:
Memento(const std::string& state) : state_(state) {}
const std::string& getState() {
return state_;
}
private:
std::string state_;
};
// 发起人类
class Originator {
public:
void setState(const std::string& state) {
state_ = state;
}
const std::string& getState() {
return state_;
}
Memento createMemento() {
return Memento(state_);
}
void restoreMemento(const Memento& memento) {
state_ = memento.getState();
}
private:
std::string state_;
};
// 管理者类
class Caretaker {
public:
void saveMemento(const Memento& memento) {
mementos_.push_back(memento);
}
Memento getMemento(int index) {
if (index >= 0 && index < mementos_.size()) {
return mementos_[index];
}
// 返回一个空的备忘录以示错误
return Memento("");
}
private:
std::vector<Memento> mementos_;
};
int main() {
Originator originator;
Caretaker caretaker;
// 设置初始状态并保存备忘录
originator.setState("State 1");
caretaker.saveMemento(originator.createMemento());
// 修改状态并保存备忘录
originator.setState("State 2");
caretaker.saveMemento(originator.createMemento());
// 恢复到第一个备忘录状态
originator.restoreMemento(caretaker.getMemento(0));
std::cout << "Current state: " << originator.getState() << std::endl;
return 0;
}
在这个示例中,Originator
类表示发起人,它有一个状态需要保存。Memento
类表示备忘录,它可以保存发起人的状态。Caretaker
类表示管理者,它可以保存和管理备忘录。
在 main
函数中,我们设置了初始状态,并保存了备忘录。然后,修改状态并再次保存备忘录。最后,我们恢复到第一个备忘录状态,从而实现了状态的撤销和恢复操作。备忘录模式非常有用,特别是在需要实现撤销和恢复功能的应用中。
桥接模式(Bridge Pattern)是一种结构型设计模式,它用于将抽象部分与实现部分分离,以便它们可以独立地变化。桥接模式的目的是将继承关系转化为组合关系,从而减少类之间的耦合度,提高系统的可扩展性。
桥接模式包含以下几个主要角色:
桥接模式的主要优点包括:
以下是一个简单的桥接模式的 C++ 示例:
#include
// 实现部分接口
class Implementor {
public:
virtual void operationImpl() = 0;
};
// 具体实现部分 A
class ConcreteImplementorA : public Implementor {
public:
void operationImpl() override {
std::cout << "Concrete Implementor A operation" << std::endl;
}
};
// 具体实现部分 B
class ConcreteImplementorB : public Implementor {
public:
void operationImpl() override {
std::cout << "Concrete Implementor B operation" << std::endl;
}
};
// 抽象部分
class Abstraction {
public:
Abstraction(Implementor* implementor) : implementor_(implementor) {}
virtual void operation() {
implementor_->operationImpl();
}
private:
Implementor* implementor_;
};
// 扩展抽象部分
class RefinedAbstraction : public Abstraction {
public:
RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {}
void additionalOperation() {
std::cout << "Additional operation" << std::endl;
}
};
int main() {
Implementor* implA = new ConcreteImplementorA();
Implementor* implB = new ConcreteImplementorB();
Abstraction* abstraction1 = new Abstraction(implA);
abstraction1->operation();
Abstraction* abstraction2 = new RefinedAbstraction(implB);
abstraction2->operation();
static_cast<RefinedAbstraction*>(abstraction2)->additionalOperation();
delete implA;
delete implB;
delete abstraction1;
delete abstraction2;
return 0;
}
在这个示例中,我们有两个实现部分:ConcreteImplementorA
和 ConcreteImplementorB
,它们实现了 Implementor
接口。然后,我们有抽象部分 Abstraction
和扩展抽象部分 RefinedAbstraction
,它们使用实现部分来完成操作。
在 main
函数中,我们创建了两个不同的实现部分,然后分别将它们与抽象部分和扩展抽象部分组合。通过这种方式,我们可以轻松地改变抽象部分和实现部分的组合,实现不同的操作。这是桥接模式的典型应用。
解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一种语言的文法规则,并提供一个解释器来解释语言中的表达式。该模式将一个句子(语法)分解成一系列的解释动作。解释器模式常用于编译器、解析器和领域特定语言的实现中。
解释器模式包含以下几个主要角色:
interpret
方法用于解释表达式。interpret
方法用于解释终结符表达式。interpret
方法用于解释非终结符表达式。解释器模式的主要优点是可以扩展语言的语法,以及在一些特定领域中解决问题。然而,它也有一些缺点,例如对于复杂的文法规则,解释器模式可能会变得复杂,难以维护。
以下是一个简单的解释器模式的 C++ 示例:
#include
#include
// 抽象表达式
class Expression {
public:
virtual int interpret(std::unordered_map<char, int>& context) = 0;
};
// 终结符表达式
class TerminalExpression : public Expression {
public:
TerminalExpression(char variable) : variable_(variable) {}
int interpret(std::unordered_map<char, int>& context) override {
return context[variable_];
}
private:
char variable_;
};
// 非终结符表达式
class NonterminalExpression : public Expression {
public:
NonterminalExpression(Expression* left, Expression* right) : left_(left), right_(right) {}
int interpret(std::unordered_map<char, int>& context) override {
return left_->interpret(context) + right_->interpret(context);
}
private:
Expression* left_;
Expression* right_;
};
int main() {
std::unordered_map<char, int> context;
context['a'] = 5;
context['b'] = 10;
Expression* expression = new NonterminalExpression(
new TerminalExpression('a'),
new TerminalExpression('b')
);
int result = expression->interpret(context);
std::cout << "Result: " << result << std::endl;
delete expression;
return 0;
}
在这个示例中,我们创建了一个简单的表达式语言,包括终结符表达式和非终结符表达式。通过解释器模式,我们可以解释这些表达式并计算结果。这个示例是解释器模式的一个简单演示,实际应用中可能会涉及更复杂的语法和解释器。
设计模式是一种通用的解决问题的模板或蓝图,它们用于解决特定类型的问题,并为软件设计提供了可重用的解决方案。在计算机科学中,有23种广泛接受的经典设计模式,它们通常被分为以下几个类别:
创建型模式(Creational Patterns):这些模式关注对象的创建机制,以便以适当的方式创建对象,隐藏创建的细节。创建型模式包括:
结构型模式(Structural Patterns):这些模式处理对象之间的组合,以便形成更大的结构。结构型模式包括:
行为型模式(Behavioral Patterns):这些模式关注对象之间的通信、职责分配和协作。行为型模式包括:
这些经典的设计模式提供了在特定情况下解决问题的有效方法,它们有助于提高软件的可维护性、可扩展性和可重用性。根据应用场景和需求,开发人员可以选择适当的设计模式来构建更健壮、可维护和可扩展的软件系统。