C++设计模式一一行为型模式

行为型模式

我们这里介绍两种对象行为型模式

  • COMMAND 命令模式

  • OBSERVER 观察者模式

命令模式

命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。

命令模式也支持可撤销的操作。
命令对象将动作和接受者包进对象中,这个对象只暴露一个execute()方法。
当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式。

UML图

例子:

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
/* 遥控器上有一个插槽,可以放上不同的装置,
* 然后用按钮控制。我们这里放置电灯,
* 并有开和关按钮。
* 可以命令模式实现
*/
#include <iostream>
using namespace std;
// 电灯类
class Light {
public:
void on() {
cout << "Light on !" << endl;
}
void off() {
cout << "Light off !" << endl;
}
};
// 命令类
class Command {
public:
virtual void execute() {}
};
// 具体命令类
class LightOnCommand : public Command {
public:
LightOnCommand(Light* lig) : light(lig) {}
// execute 方法
void execute() {
light->on();
}
private:
Light* light;
};
class LightOffCommand : public Command {
public:
LightOffCommand(Light* lig) : light(lig) {}
void execute() {
light->off();
}
private:
Light* light;
};
// 遥控器类
class RemoteControl {
public:
void setCommand(Command* command) {
slot = command;
}
void buttonOn() {
slot->execute();
}
private:
Command* slot;
};
int main() {
RemoteControl lightOnControl;
RemoteControl lightOffControl;
Command* onCommand = new LightOnCommand(new Light());
Command* offCommand = new LightOffCommand(new Light());
lightOnControl.setCommand(onCommand);
lightOffControl.setCommand(offCommand);
lightOnControl.buttonOn();
lightOffControl.buttonOn();
return 0;
}

测试结果:

观察者模式

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

UML图

例子:

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
/* 气象系统有三个部分分别是
* 气象站(获取实际气象数据的物理装置),
* WeatherData对象(用来追踪来自气象站的数据,并更新布告板)
* 和布告板(显示目前天气状况给用户看)。
* WeatherData对象知道如何根物理气象站联系,以取得更新信息。
* WeatherData对象会随机更新三个布告板的显示:
* 目前状况(温度,湿度,气压)、气象统计和天气预报。
* 我们的工作是建立一个 应用,
* 利用WeatherData对象取得数据,
* 并更新三个布告板:目前状况、气象统计和天气预报。
*/
#include <iostream>
#include <list>
using namespace std;
//以下是观察者和主题的基类,其中DisplayElement是一个抽象类,用来
//使子类实现显示功能
class Observer {
public:
virtual ~Observer() {};
virtual void update(float temp, float humidity, float pressure) {}; // humidity 湿度
};
class DisplayElement {
public:
virtual ~DisplayElement() {};
virtual void display() = 0;
};
class Subject {
public:
virtual ~Subject() {};
virtual void regsiterObserver(Observer* o) {};
virtual void removeObserver(Observer* o) {};
virtual void notifyObserver() {};
};
// WeatherData类,实现了注册,删除和通知观察者的功能
class WeatherData : public Subject {
public:
void regsiterObserver(Observer *o) {
observers.push_back(o);
}
void removeObserver(Observer *o) {
observers.remove(o);
}
void notifyObservers() {
list<Observer*>::iterator iter = observers.begin();
for (; iter != observers.end(); iter++) {
Observer* observer = *iter;
observer->update(tempreature, humidity, pressure);
}
}
void measurementsChanged() {
notifyObservers();
}
void setMeasurements(float temp, float humid, float pres) {
tempreature = temp;
humidity = humid;
pressure = pres;
measurementsChanged();
}
private:
list<Observer*> observers;
float tempreature;
float humidity;
float pressure;
};
//以下是CurrentConditionsDisplay布告板的实现,主要功能为申请注册,实时更新和显示。
class CurrentConditionDisplay : public Observer, public DisplayElement {
public:
CurrentConditionDisplay(Subject *weather_Data) {
weatherData = weather_Data;
weatherData->regsiterObserver(this);
}
void update(float temp, float humid, float pres) {
tempreature = temp;
humidity = humid;
// pressure = pres;
display();
}
void display() {
cout << "Current conditions: " << tempreature << "F degree and " << humidity << "% humidity" << endl;
}
private:
float tempreature;
float humidity;
Subject *weatherData;
};
int main() {
WeatherData *weatherData = new WeatherData();
CurrentConditionDisplay *currentConditionDisplay = new CurrentConditionDisplay(weatherData);
weatherData->setMeasurements(80, 65, 30.4f);
weatherData->setMeasurements(82, 70, 29.2f);
weatherData->setMeasurements(78, 90, 29.2f);
return 0;
}

测试结果: