行为型设计模式 (Behavioral Design Patterns)- 11种

[TOC]

什么是行为型设计模式

行为型设计模式(Behavioral Design Patterns)是软件设计模式中的一类,用于描述对象之间的交互和通信方式,关注对象的行为和相互作用。行为型设计模式通常用于处理对象之间的算法、责任、状态等行为相关的问题,以实现更灵活、可复用、可扩展的软件系统。

行为型设计模式包括以下十一种常见的模式:

  1. 责任链模式(Chain of Responsibility Pattern):将请求的发送者和接收者解耦,通过一条链式的方式依次处理请求,直到找到合适的处理者。
  2. 命令模式(Command Pattern):将请求封装成一个对象,并将其发送给不同的接收者,从而将请求的发送者和接收者解耦。
  3. 解释器模式(Interpreter Pattern):定义了一种语言的文法和解释器,用于解释和执行特定的语言表达式。
  4. 迭代器模式(Iterator Pattern):提供一种一致的方式来遍历集合对象中的元素,而不暴露其内部结构。
  5. 中介者模式(Mediator Pattern):将对象之间的相互调用和通信封装到一个中介者对象中,从而减少对象之间的直接依赖关系。
  6. 备忘录模式(Memento Pattern):在不破坏封装性的前提下,保存和恢复对象的内部状态。
  7. 观察者模式(Observer Pattern):定义了一种一对多的关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。
  8. 状态模式(State Pattern):允许对象在内部状态发生改变时改变其行为,从而看起来像是改变了其类。
  9. 策略模式(Strategy Pattern):定义了一系列算法,并将其封装成独立的对象,使得它们可以相互替换,从而在运行时动态选择不同的算法。
  10. 模板方法模式(Template Method Pattern):定义一个算法骨架,将其中的某些步骤延迟到子类中实现,从而在不改变算法结构的情况下,可以通过子类来改变算法的具体实现。
  11. 访问者模式(Visitor Pattern):将对一个复杂对象的操作分离成多个独立的操作,从而可以在不改变对象结构的情况下增加新的操作。

一、责任链模式(Chain of Responsibility Pattern)

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,用于将处理请求的对象组成一条链,并在该链上依次处理请求,直到找到合适的处理者为止。责任链模式将请求的发送者和接收者解耦,使得多个对象都有机会处理请求,从而避免了将请求发送给固定的接收者。

在责任链模式中,通常会将处理者组成一条链,并将请求从链的起始点发送给第一个处理者,然后该处理者可以选择处理请求或者将请求传递给链上的下一个处理者,依次类推,直到找到合适的处理者或者请求到达链的末尾。这样可以实现一种请求处理的流程,不同的处理者可以根据自己的逻辑来处理请求,从而实现灵活的请求处理方式。

意图:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。

Chain of Responsibility Pattern适用于:

  1. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
  2. 想在不明确指定接收者的情况下向多个对象种的一个提交请求。
  3. 可处理一个请求的对象集合应被动态指定。

责任链模式结构图

责任链模式的主要角色包括:
  1. 抽象处理者(Handler)

    定义了处理请求的接口,通常包含一个处理请求的方法,以及设置和获取下一个处理者的方法。

  2. 具体处理者(Concrete Handler)

    实现了抽象处理者接口,具体处理请求的逻辑,并可以选择将请求传递给下一个处理者。

  3. 客户端(Client)

    创建并组织责任链,将请求发送给第一个处理者,并负责将请求传递给下一个处理者,直到找到合适的处理者。

责任链模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <string>
using namespace std;

/*
* 责任链模式
*/

// 抽象处理者
class Handler
{
protected:
Handler* next;
public:
Handler(Handler* n = nullptr) :next(n) {}
void SetNext(Handler* n) { next = n; }
virtual void HandlerRequest(int request) = 0;
virtual ~Handler() {}
};

// 具体处理者A
class HandlerA :public Handler
{
public:
void HandlerRequest(int request) override
{
if (request <= 7)
{
cout << "HandlerA 的处理完成!" << endl;
}
else if (next)
{
next->HandlerRequest(request);
}
else
{
cout << "无法处理请求!" << endl;
}
}
};

// 具体处理者B
class HandlerB :public Handler
{
public:
void HandlerRequest(int request) override
{
if (request <= 15)
{
cout << "HandlerB 的处理完成!" << endl;
}
else if (next)
{
next->HandlerRequest(request);
}
else
{
cout << "无法处理请求!" << endl;
}
}
};

// 具体处理者C
class HandlerC :public Handler
{
public:
void HandlerRequest(int request) override
{
if (request <= 30)
{
cout << "HandlerC 的处理完成!" << endl;
}
else if (next)
{
next->HandlerRequest(request);
}
else
{
cout << "无法处理请求!" << endl;
}
}
};

int main()
{
Handler* handlerA = new HandlerA();
Handler* handlerB = new HandlerB();
Handler* handlerC = new HandlerC();
handlerA->SetNext(handlerB);
handlerB->SetNext(handlerC);

handlerA->HandlerRequest(5);
handlerA->HandlerRequest(10);
handlerA->HandlerRequest(25);
handlerA->HandlerRequest(35);
}

二、 命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为型设计模式,用于将请求封装成一个对象,从而允许客户端通过不同的请求对象来参数化和传递请求,使得请求的发出者和接收者解耦。命令模式将请求的发送者(客户端)和请求的接收者(执行者)分离,通过引入一个命令对象来间接地传递请求,从而实现了请求的解耦和灵活性。

命令模式的核心思想是将请求封装成一个对象,从而可以实现请求的参数化、传递、撤销等操作,同时也可以实现请求的队列、日志、事务等功能。命令模式通常适用于需要将请求的发出者和接收者解耦的场景,例如,需要实现撤销、重做、延迟执行等功能的应用场景。

意图:将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

Command Pattern四适用于:

  1. 抽象出待执行的动作以参数化某对象。
  2. 在不同的时刻指定、排列和执行请求。
  3. 支持取消操作。
  4. 支持修改日志。
  5. 用构建在原语操作上的高层操作构造一个系统。

命令模式结构图

命令模式的主要角色包括:
  1. 命令接口(Command Interface)

    定义了执行命令的接口,通常包含一个或多个抽象方法,如 Execute() 方法。

  2. 具体命令(Concrete Command)

    实现了命令接口,具体命令对象通常包含了对请求的接收者的引用,以及具体的执行逻辑。

  3. 请求接收者(Receiver)

    执行命令所要求的操作,实际完成请求的处理。

  4. 请求发送者(Client)

    负责创建命令对象,并将命令对象发送给请求的接收者,请求发送者通常持有一个命令对象,可以通过命令对象来发出请求。

命令模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <iostream>
#include <string>
using namespace std;

/*
* 命令链模式
*/

// 请求接收者
class Receiver
{
public:
void Action1()
{
cout << "接收者执行动作1" << endl;
}
void Action2()
{
cout << "接收者执行动作2" << endl;
}
~Receiver() { ; }
};

// 命令接口
class Command
{
public:
virtual ~Command() { ; }
virtual void Execute() = 0;
};

// 具体命令1
class Command1 :public Command
{
private:
Receiver* receiver;
public:
Command1(Receiver* r) :receiver(r) { ; }
~Command1() { ; }
void Execute()
{
cout << "执行具体命令1" << endl;
receiver->Action1();
}
};

// 具体命令2
class Command2 :public Command
{
private:
Receiver* receiver;
public:
Command2(Receiver* r) :receiver(r) { ; }
~Command2() { ; }
void Execute()
{
cout << "执行具体命令2" << endl;
receiver->Action2();
}
};

// 命令调用者
class Invoker
{
private:
Command* command;
public:
void SetCommand(Command* cmd)
{
command = cmd;
}
void ExcuteCommand()
{
if (command)
{
command->Execute();
}
}
~Invoker() { ; }
};

int main()
{
Receiver* receiver = new Receiver();

Command* command1 = new Command1(receiver);
Command* command2 = new Command2(receiver);

Invoker* invoker = new Invoker();
invoker->SetCommand(command1);
invoker->ExcuteCommand();

invoker->SetCommand(command2);
invoker->ExcuteCommand();
}

三、解释器模式(Interpreter Pattern)

解释器模式(Interpreter Pattern)是一种行为型设计模式,用于处理如何解释和执行特定语言或规则的问题。它定义了一种语言的文法表示,并且可以用于解释语言中的表达式。通过使用解释器模式,可以将一个问题或表达式表示为一个语法树,并且可以在运行时递归地对语法树进行解释和求值。

解释器模式的主要目的是将一个问题或表达式转化为一种可以解释的数据结构,并且提供一种灵活的方式来解释和执行这些数据结构,从而实现对复杂规则和语言的处理。

意图:给定一个语言,定于它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言种的句子。

Interpreter Pattern适用于:

  1. 当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,一下效果最好:
  • 该文法简单。
  • 效率不是一个关键问题。

解释器模式结构图

解释器模式通常包含以下角色:
  1. 抽象表达式(Abstract Expression)

    定义了解释器的接口,包含一个解释方法(interpret)用于解释表达式。

  2. 终结符表达式(Terminal Expression)

    实现抽象表达式接口,用于表示语言中的终结符,也就是不再可以解释的最小单元。

  3. 非终结符表达式(Non-terminal Expression)

    实现抽象表达式接口,用于表示语言中的非终结符,它包含了一个或多个子表达式,并且可以递归地进行解释。

  4. 上下文(Context)

    包含了解释器需要的全局信息,可以在解释器中共享。

  5. 客户端(Client)

    使用解释器模式的客户端,负责创建、配置和使用解释器模式的对象。

解释器模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <iostream>
#include <string>
using namespace std;

/*
* 解释器模式
*/

// 抽象表达式类
class Expression
{
public:
virtual ~Expression() { ; }
virtual int interpret() = 0;
};

// 终结符表达式:数字
class NumberExpression :public Expression
{
private:
int number;
public:
NumberExpression(int num) :number(num) {}
~NumberExpression() { ; }
int interpret() override
{
return number;
}
};

// 非终结符表达式:加法
class AddExpression :public Expression
{
private:
Expression* left;
Expression* right;
public:
AddExpression(Expression* l, Expression* r) :left(l), right(r) {}
~AddExpression() { ; }
int interpret() override
{
return left->interpret() + right->interpret();
}
};

// 非终结符表达式:乘法
class MulExpression :public Expression
{
private:
Expression* left;
Expression* right;
public:
MulExpression(Expression* l, Expression* r) :left(l), right(r) {}
~MulExpression() { ; }
int interpret() override
{
return left->interpret() * right->interpret();
}
};

// 解释器上下文
class Context
{
private:
Expression* expression;
public:
void setExpression(Expression* exp)
{
expression = exp;
}
int interpret()
{
if (expression)
{
return expression->interpret();
}
return 0;
}
~Context() { ; }
};

int main()
{
Expression* number1 = new NumberExpression(1);
Expression* number2 = new NumberExpression(2);

Expression* addExpression = new AddExpression(number1, number2);

Context context;
context.setExpression(addExpression);

int result = context.interpret();
cout << "result: " << result << endl;
cout << "=================================" << endl;
Expression* number3 = new NumberExpression(3);
Expression* number4 = new NumberExpression(4);
Expression* mulExpression = new MulExpression(number3, number4);
context.setExpression(mulExpression);
result = context.interpret();
cout << "result: " << result << endl;
}

四、迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种在集合对象中遍历元素的方式,而无需暴露集合对象的内部结构。通过使用迭代器模式,可以让客户端代码更加简洁和灵活地遍历集合对象中的元素,同时也减少了与集合对象的耦合。

意图:提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。

Iterator Pattern适用于:

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 支持对聚合对象的多种遍历。
  3. 为遍历不同的聚合结构提供一个同一的接口。

迭代器模式

迭代器模式通常包含以下角色:
  1. 迭代器(Iterator)

    定义了遍历集合对象的接口,包括了访问集合中下一个元素、获取当前元素、判断是否还有下一个元素等方法。

  2. 集合(Collection)

    定义了集合对象的接口,包括了添加、删除、获取迭代器等方法,用于管理和操作集合中的元素。

迭代器模式实现参考代码
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
#include <iostream>
#include <vector>
using namespace std;

/*
* 迭代器模式
*/

// 迭代器接口
class Iterator
{
public:
virtual int next() = 0;
virtual bool hasNext() = 0;
};

// 集合接口
class Collection
{
public:
virtual Iterator* CreateIterator() = 0;
};

// 具体迭代器1
class Iterator1 :public Iterator
{
private:
vector<int> collection;
int index;
public:
Iterator1(vector<int> coll) :collection(coll), index(0) { ; }
int next() override
{
return collection[index++];
}
bool hasNext() override
{
return index < collection.size();
}
};

// 具体集合1
class Collection1 :public Collection
{
private:
vector<int> collection;
public:
void Add(int num)
{
collection.push_back(num);
}
Iterator* CreateIterator() override
{
return new Iterator1(collection);
}
};

int main()
{
Collection1 collection1;
collection1.Add(1);
collection1.Add(2);
collection1.Add(3);

Iterator* iterator = collection1.CreateIterator();
while (iterator->hasNext())
{
cout << iterator->next() << " ";
}
cout << std::endl;
}

五、中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是一种行为型设计模式,用于解耦多个对象之间的复杂交互关系,通过引入一个中介者对象,将对象之间的交互集中管理和控制。中介者模式通过将对象之间的通信集中到中介者对象,从而减少了对象之间的直接依赖关系,降低了耦合性,增加了系统的可维护性和扩展性。

意图:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

Mediator Pattern适用于:

  1. 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
  2. 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  3. 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

中介者模式结构图

中介者模式通常包含以下角色:
  1. 中介者(Mediator)

    中介者是一个接口或者抽象类,定义了同事对象之间的通信接口。中介者负责管理和协调同事对象之间的交互关系,通常包括注册和移除同事对象的方法,以及定义处理不同交互场景的逻辑。

  2. 具体中介者(Concrete Mediator)

    具体中介者是中介者接口的实现类,实现了同事对象之间的具体通信逻辑。具体中介者对象通常会持有对所有相关同事对象的引用,并负责处理它们之间的交互。

  3. 同事对象(Colleague)

    同事对象是需要进行通信的对象,每个同事对象持有对中介者对象的引用,并通过中介者对象来与其他同事对象进行通信。同事对象通常会实现一个接口或者继承一个抽象类,定义了与中介者对象通信的方法。

  4. 具体同事对象(Concrete Colleague)

    具体同事对象是同事对象接口的实现类,实现了与中介者对象通信的具体逻辑。具体同事对象通过调用中介者对象的方法来与其他同事对象进行通信。

中介者模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <string>
using namespace std;

/*
* 中介者模式
*/

// 中介者接口
class Mediator
{
public:
virtual void SendMessage(string message, class Colleague* colleague) = 0;
};

// 同事类接口
class Colleague
{
protected:
string message;
Mediator* mediator;
public:
Colleague(Mediator* m) :mediator(m) { ; }
virtual void ReceiveMessage(string message) = 0;
virtual void SendMessage(string message) = 0;
};

// 具体同事A
class ColleagueA :public Colleague
{
public:
ColleagueA(Mediator* m) :Colleague(m) { ; }
virtual void ReceiveMessage(string message) override
{
cout << "ColleagueA receive message: " << message << endl;
}
virtual void SendMessage(string message) override
{
mediator->SendMessage(message, this);
}
};

// 具体同事B
class ColleagueB :public Colleague
{
public:
ColleagueB(Mediator* m) :Colleague(m) { ; }
virtual void ReceiveMessage(string message) override
{
cout << "ColleagueB receive message: " << message << endl;
}
virtual void SendMessage(string message) override
{
mediator->SendMessage(message, this);
}
};

class ConcreteMediator :public Mediator
{
private:
Colleague* colleagueA;
Colleague* colleagueB;
public:
void SetColleagueA(Colleague* colleague) { colleagueA = colleague; }
void SetColleagueB(Colleague* colleague) { colleagueB = colleague; }
void SendMessage(string message, Colleague* colleague) override
{
if (colleague == colleagueA)
{
colleagueB->ReceiveMessage(message);
}
else if (colleague == colleagueB)
{
colleagueA->ReceiveMessage(message);
}
}
};

int main()
{
ConcreteMediator* mediator = new ConcreteMediator();

Colleague* colleagueA = new ColleagueA(mediator);
Colleague* colleagueB = new ColleagueB(mediator);
mediator->SetColleagueA(colleagueA);
mediator->SetColleagueB(colleagueB);
colleagueA->SendMessage("你好啊!同事B");
colleagueB->SendMessage("你好啊!同事A");
}

六、备忘录模式(Memento Pattern)

备忘录模式(Memento Pattern)是一种行为型设计模式,用于在不破坏对象封装性的前提下,捕获和恢复对象的内部状态。备忘录模式通过在不同的对象间保存对象状态的快照,使得对象可以在后续需要时还原到之前的状态。

备忘录模式的核心思想是通过将对象的状态保存到外部的备忘录对象中,从而实现了状态的可保存和可恢复性。发起人对象可以根据需要创建备忘录对象,并将自己的状态保存到备忘录中。管理者对象可以保存备忘录对象,也可以从备忘录对象中恢复发起人对象的状态,从而实现了对象状态的历史记录和撤销/恢复功能。

意图:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

Memento Pattern适用于:

  1. 必须保存一个对象在某一时刻的(部分状态),这样以后需要时,它才能恢复到先前的状态。
  2. 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。

备忘录模式结构图

备忘录模式通常包含以下角色:
  1. 发起人(Originator)

    负责创建和持有需要保存状态的对象,并可以通过创建备忘录来保存其内部状态。

  2. 备忘录(Memento)

    用于存储发起人的内部状态,包含了需要保存的状态信息。

  3. 管理者(Caretaker)

    负责管理备忘录对象,可以保存多个备忘录对象,并在需要时将其还原给发起人。

备忘录模式实现参考代码
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
73
74
75
76
77
#include <iostream>
#include <string>
using namespace std;

/*
* 备忘录模式
*/

// 备忘录类
class Memento
{
private:
string state;
public:
Memento() { ; }
Memento(string s)
{
state = s;
}
string GetState()
{
return state;
}
};

// 原发器
class Originator
{
private:
string state;
public:
Originator(string s) :state(s) { ; }
void SetState(string s)
{
state = s;
}
string GetState()
{
return state;
}
Memento CreateMemento()
{
return Memento(state);
}
void SetMemento(Memento memento)
{
state = memento.GetState();
}
};

// 管理者类
class Caretaker
{
private:
Memento memento;
public:
void SaveMemento(const Memento& m)
{
memento = m;
}
Memento RetrieveMemento()
{
return memento;
}
};

int main()
{
Caretaker caretaker;
Originator originator("状态1");
cout << "初始状态:" << originator.GetState() << endl;
caretaker.SaveMemento(originator.CreateMemento());
originator.SetState("状态2");
cout << "修改状态:" << originator.GetState() << endl;
originator.SetMemento(caretaker.RetrieveMemento());
cout << "恢复状态:" << originator.GetState() << endl;
}

七、观察者模式(Observer Pattern)

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系,当一个对象的状态发生变化时,其所有依赖对象都会得到通知并自动更新。

观察者模式的核心思想是解耦对象之间的依赖关系,让主题和观察者之间通过接口进行通信,从而实现了松耦合的设计。当主题的状态发生变化时,观察者会被自动通知,并根据需要进行相应的处理,从而实现了对象间的动态协作和响应式的行为。观察者模式常用于事件处理、GUI编程、消息系统等场景。

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到了通知并被自动更新。

Observer Pattern适用于:

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
  2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
  3. 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的。

观察者模式结构图

观察者模式通常包含以下角色:
  1. 主题(Subject)

    也称为被观察者或发布者,负责维护一组观察者对象,并通知它们自己的状态变化。

  2. 观察者(Observer)

    也称为订阅者或观察者,定义了一个更新接口,用于接收主题通知的更新。

  3. 具体主题(Concrete Subject)

    实现了主题接口,负责维护自己的状态,并在状态发生变化时通知所有观察者。

  4. 具体观察者(Concrete 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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <vector>
#include <string>
using namespace std;

/*
* 观察者模式
*/

// 抽象观察者类
class Observer
{
public:
virtual void Update() = 0;
};

// 抽象主题类
class Subject
{
public:
virtual void Attach(Observer* observer) = 0;
virtual void Detach(Observer* observer) = 0;
virtual void Notify() = 0;
};

// 具体观察者1
class Observer1 :public Observer
{
private:
string name;
Subject* subject;
public:
Observer1(string n, Subject* s) :name(n), subject(s)
{
subject->Attach(this);
}
Observer1(string n) :name(n) { ; }
void Update() override
{
cout << "观察者:" << name << "收到更新通知!" << endl;
}
};

// 具体观察者2
class Observer2 :public Observer
{
private:
string name;
Subject* subject;
public:
Observer2(string n, Subject* s) :name(n), subject(s)
{
subject->Attach(this);
}
Observer2(string n) :name(n) { ; }
void Update() override
{
cout << "观察者:" << name << "收到更新通知!" << endl;
}
};

// 具体主题1
class Subject1 :public Subject
{
private:
vector<Observer*> observers;
public:
void Attach(Observer* observer) // 添加观察者
{
observers.push_back(observer);
}
void Detach(Observer* observer) // 删除观察者
{
for (auto it = observers.begin(); it != observers.end(); ++it)
{
if (*it == observer)
{
observers.erase(it);
break;
}
}
}
void Notify() // 通知观察者
{
cout << "通知所有的观察者..." << endl;
for (auto it : observers)
{
it->Update();
}
}
};

int main()
{
Subject1* subject1 = new Subject1();
Observer* observer1 = new Observer1("observer1", subject1);
Observer* observer2 = new Observer2("observer2", subject1);
//Observer* observer1 = new Observer1("observer1");
//Observer* observer2 = new Observer2("observer2");
//subject1->Attach(observer1);
//subject1->Attach(observer2);
subject1->Notify();
cout << "==========分割线=============" << endl;
subject1->Detach(observer2);
subject1->Notify();
}

八、状态模式(State Pattern)

状态模式(State Pattern)是一种行为型设计模式,用于在对象的状态发生变化时,使对象能够改变其行为,而不需要通过多个条件语句来实现。状态模式将对象的行为封装在不同的状态对象中,使得状态之间可以相互切换,从而实现对象在不同状态下的不同行为。

状态模式的主要目的是将对象的行为和状态分离,使得对象的行为能够根据不同的状态发生变化,从而实现更灵活、可扩展和易维护的代码。它适用于对象在不同状态下需要有不同行为的场景,避免了大量的条件语句,使代码更加清晰、简洁和可维护。

意图:允许一个对象在内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

State Pattern适用于:

  1. 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。

状态模式结构图

状态模式通常包含以下角色:
  1. 环境(Context)

    负责维护一个当前状态对象的引用,并将与状态相关的请求委派给当前状态处理。

  2. 抽象状态(State)

    定义状态的接口,通常包含了处理请求的方法。

  3. 具体状态(Concrete State)

    实现抽象状态的接口,并定义了在该状态下的具体行为。

状态模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <iostream>
#include <vector>
#include <string>
#include <typeinfo>
using namespace std;

/*
* 状态者模式
*/

class Context; // 前向声明
class StateA; // 前向声明

// 抽象状态类
class State
{
public:
virtual void Handle(Context* context) = 0;
};

// 状态类B
class StateB :public State
{
public:
void Handle(Context* context) override;
};

// 状态类A
class StateA :public State
{
public:
void Handle(Context* context) override;
};

// 贩卖机
class Context
{
private:
int count;
State* state;
public:
Context()
{
count = 3;
state = new StateA();
}
int GetCount()
{
return count;
}
void SetCount(int c)
{
count = c;
}
State* GetState()
{
return state;
}
void SetState(State* s)
{
state = s;
}
void Request()
{
state->Handle(this);
}
};

// StateA 类成员函数定义
void StateA::Handle(Context* context)
{
int count = context->GetCount();
if (count >= 1)
{
cout << "购买成功!" << endl;
context->SetCount(count - 1);
if (count - 1 == 0)
{
context->SetState(new StateB());
}
}
else
{
cout << "库存无货,购买失败!" << endl;
}
}

// StateB 类成员函数定义
void StateB::Handle(Context* context)
{
int count = context->GetCount();
if (count == 0)
{
cout << "库存无货,购买失败!" << endl;
context->SetCount(5);
cout << "补货成功,可重新购买!" << endl;
}
}

int main()
{
Context* context = new Context();
cout << typeid(*context->GetState()).name() << endl;
context->Request();
context->Request();
context->Request();
cout << typeid(*context->GetState()).name() << endl;
context->Request();
cout << typeid(*context->GetState()).name() << endl;
}

九、策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时根据需要选择不同的算法或策略来完成特定的任务,而不需要在代码中硬编码这些算法或策略。策略模式通过将算法或策略封装成独立的类,并通过一个统一的接口进行调用,实现了算法或策略的独立切换和替换。

策略模式在实际应用中可以用于很多场景,例如在排序算法、支付方式、日志记录等场景中,根据不同的需求选择不同的策略来完成任务。

意图:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换,此模式使得算法可以独立于使用它们的客户而变化。

Strategy Pattern适用于:

  1. 许多相关的类仅仅是行为有异。”策略“提供了一种用多个行为中的一个行为来配置一个类的方法。
  2. 需要使用一个算法的不同变体。
  3. 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
  4. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的Strategy类中,以替代这些条件语句。

策略模式结构图

策略模式通常包含以下角色:
  1. 环境类(Context)

    它包含一个策略接口的引用,并在运行时根据需要调用策略对象的方法来完成任务。

  2. 策略接口(Strategy)

    它定义了策略模式的接口,通常包含一个或多个方法,用于描述不同的算法或策略。

  3. 具体策略类(Concrete Strategy)

    它实现了策略接口,并实现了具体的算法或策略。在运行时,环境类可以根据需要选择合适的具体策略类来完成任务。

策略模式实现参考代码
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
#include <iostream>
using namespace std;

/*
* 策略模式
*/

// 策略接口
class Strategy
{
public:
virtual void TwoNumberOperation(int a, int b) = 0;
};

// 具体策略A
class StrategyA :public Strategy
{
public:
void TwoNumberOperation(int a, int b) override
{
cout << a + b << endl;
}
};

// 具体策略B
class StrategyB :public Strategy
{
public:
void TwoNumberOperation(int a, int b) override
{
cout << a - b << endl;
}
};

// 具体策略C
class StrategyC :public Strategy
{
public:
void TwoNumberOperation(int a, int b) override
{
cout << a * b << endl;
}
};

class Context
{
protected:
Strategy* strategy;
public:
Context(Strategy* s) { strategy = s; }
void Operation(int a, int b)
{
strategy->TwoNumberOperation(a, b);
}
};

int main()
{
Strategy* strategyA = new StrategyA();
Strategy* strategyB = new StrategyB();
Strategy* strategyC = new StrategyC();
Context* context = new Context(strategyA);
context->Operation(2, 3);
context = new Context(strategyB);
context->Operation(2, 3);
context = new Context(strategyC);
context->Operation(2, 3);
}

十、模板方法模式(Template Method Pattern)

模板方法模式(Template Method Pattern)是一种行为型设计模式,用于定义一个算法的骨架,将一些步骤的实现延迟到子类中,从而使子类可以重新定义算法的某些特定步骤,而不改变算法的结构。

在模板方法模式中,定义一个抽象基类(或接口),其中包含了一个模板方法(Template Method),该方法是一个算法的骨架,包含了一系列的步骤,其中某些步骤可以是抽象的,留给子类实现。这样子类可以根据自身的需求,提供具体的实现,从而影响算法的行为。

意图:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

Template Method Pattern适用于:

  1. 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  2. 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。
  3. 控制子类扩展。模板方法旨在特定点调用“hook”操作(默认的行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。

模板方法模式结构图

模板方法模式通常包含以下角色:
  1. 抽象基类(Abstract Class)

    定义了模板方法,包含了一系列的抽象和具体方法,是模板方法模式的核心。

  2. 具体子类(Concrete Class)

    继承抽象基类,实现抽象方法,从而提供具体的实现。

模板方法模式实现参考代码
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
#include <iostream>
#include <string>
using namespace std;

/*
* 模板方法模式
*/

class Person
{
public:
void TemplateMethod()
{
cout << "去教室" << endl;
PrimitiveOperation1();
cout << "离开教室" << endl;
PrimitiveOperation2();
}
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
};

class Student :public Person
{
void PrimitiveOperation1()
{
cout << "学生听课" << endl;
}
void PrimitiveOperation2()
{
cout << "学生写作业" << endl;
}
};

class Teacher :public Person
{
void PrimitiveOperation1()
{
cout << "老师上课" << endl;
}
void PrimitiveOperation2()
{
cout << "老师布置作业" << endl;
}
};

int main()
{
Person* student = new Student();
Person* teacher = new Teacher();
student->TemplateMethod();
cout << "================================" << endl;
teacher->TemplateMethod();
}

十一、访问者模式(Visitor Pattern)

访问者模式(Visitor Pattern)是一种行为型设计模式,用于在不修改已有对象结构的情况下,定义对这些对象结构中各个元素的新操作。访问者模式通过将对元素的操作封装成独立的访问者类,使得可以在不修改元素类的情况下,新增、扩展或变化元素的操作。

需要注意的是,访问者模式在设计时需要谨慎使用,一般适用于对一组对象的操作比较稳定、固定,并且需要对这组对象进行不同的操作,而不是对每个对象进行不同的操作。

意图:表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。

Visitor Pattern适用于:

  1. 一个对象结构包含很多类对象,它们有不同的接口,而用户相对这些对象实施一些依赖于其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同的并且不想关的操作,而又想要避免这些操作“污染”这些对象的类。Visitor 使得用户可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用 Visitor 模式让每个应用仅包含需要用到的操作。
  3. 定于对象结构体的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价,如果对象结构类经常改变,那么还是在这些类中定义这些操作较好。

访问者模式结构图

访问者模式通常包含以下角色:
  1. 访问者(Visitor)

    定义了对每个元素的访问操作接口,可以通过这个接口访问元素的各个部分。

  2. 元素(Element)

    定义了一个接受访问者的接口,使得访问者可以访问自己的内部元素结构,并可以对这些结构进行操作。

访问者模式实现参考代码
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <vector>
#include <string>
using namespace std;

/*
* 访问者模式
*/

class ElementA;
class ElementB;

// 访问者接口
class Visitor
{
public:
virtual void visit(ElementA* elementA) = 0;
virtual void visit(ElementB* elementB) = 0;
};

// 元素接口
class Element
{
public:
virtual void accept(Visitor* visitor) = 0;
};

// 具体元素A
class ElementA :public Element
{
public:
void accept(Visitor* visitor) override
{
visitor->visit(this);
}
void OperationA()
{
cout << "元素 A 的方法" << endl;
}
};

// 具体元素B
class ElementB :public Element
{
public:
void accept(Visitor* visitor) override
{
visitor->visit(this);
}
void OperationB()
{
cout << "元素 B 的方法" << endl;
}
};

// 具体访问者
class ConcreteVisitor :public Visitor
{
public:
void visit(ElementA* elementA) override
{
cout << "访问者访问元素 A 的方法:" << endl;
elementA->OperationA();
}
void visit(ElementB* elementB) override
{
cout << "访问者访问元素 B 的方法:" << endl;
elementB->OperationB();
}
};

// 对象结构体类
class ObjectStructure
{
private:
vector<Element*>elements;
public:
void AddElement(Element* element)
{
elements.push_back(element);
}
void accept(Visitor* visitor)
{
for (auto element : elements)
{
element->accept(visitor);
}
}
};

int main()
{
ElementA elementA;
ElementB elementB;
ConcreteVisitor visitor;
ObjectStructure objectStructure;
objectStructure.AddElement(&elementA);
objectStructure.AddElement(&elementB);
objectStructure.accept(&visitor);
}