• 主页
  • 归档
Articles Change The World About me

  • 主页
  • 归档

设计模式-行为型模式

2022-07-28 阅读量 17

0x00 引言

  设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案,之所以记录这些模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。重要的参考文献为设计模式-可复用的面向对象软件元素[1],以及菜鸟教程[2]上收录的一些成熟的设计模式。本文将根据菜鸟教程上的设计模式分类方式书写,且只针对创建型模式,全部代码基于c++。

0x01 观察者模式

  观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。
  订阅-发布模式是由观察者模式衍生出来的,前者新增了第三个组件,称为调度中心或事件通道,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

1
2
1 观察者模式
2 订阅-发布模式

1、观察者模式
  观察者模式有两个重要的角色,即目标和观察者,在目标和观察者之间是没有事件通道的。一方面,观察者要想订阅目标事件,由于没有事件通道,因此必须将自己添加到目标(Subject) 中进行管理;另一方面,目标在触发事件的时候,也无法将通知操作(notify) 委托给事件通道,因此只能亲自去通知所有的观察者。

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
#include <vector>
#include <string>
#include <iostream>

class Observer {
public:
void update(void* param) {
std::string print = *static_cast<std::string*>(param);
std::cout << print << std::endl;
}
};

class Subject {
public:
void add(Observer* observer) {
m_observers.push_back(observer);
}

void notify(void* param) {
for (int i = 0; i < m_observers.size(); ++i) {
m_observers[i]->update(param);
}
}

private:
std::vector<Observer*> m_observers;
};

int main()
{
// 创建观察者ob1
Observer* ob1 = new Observer();

// 创建观察者ob2
Observer* ob2 = new Observer();

// 创建目标sub
Subject* sub = new Subject();

// 目标sub添加观察者ob1 (目标和观察者建立了依赖关系)
sub->add(ob1);

// 目标sub添加观察者ob2
sub->add(ob2);

// 目标sub触发SMS事件(目标主动通知观察者)
std::string param = "I fired SMS event";
sub->notify(&param);
}

2、订阅-发布模式
  发布-订阅模式是面向调度中心编程的,只需要写一个类专门用于控制信息的发布。其优点在于去中心化,即不在乎谁是发布者,而且能管理多个事件。

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
#include <map>
#include <vector>
#include <string>
#include <iostream>

typedef void (* CALLBACK)(void *param);

class PubSub {
public:
void subscribe(const std::string& topic, CALLBACK callback) {
if (callback) {
m_subscribers[topic].push_back(callback);
}
}

void publish(const std::string& topic, void* param) {
std::vector<CALLBACK> cb = m_subscribers[topic];
for (int i = 0; i < cb.size(); ++i) {
CALLBACK cbFunc = cb[i];
cbFunc(param);
}
}
private:
std::map<std::string, std::vector<CALLBACK> > m_subscribers;
};

void callback(void* param)
{
std::string print = *static_cast<std::string*>(param);
std::cout << print << std::endl;
}

int main()
{
// 创建事件调度中心,为订阅者和发布者提供调度服务
PubSub* pubSub = new PubSub();

// A订阅了SMS事件(A只关注SMS本身,而不关心谁发布这个事件)
pubSub->subscribe("SMS", &callback);

// B订阅了SMS事件
pubSub->subscribe("SMS", &callback);

// C发布了SMS事件(C只关注SMS本身,不关心谁订阅了这个事件)
std::string param = "I published SMS event";
pubSub->publish("SMS", &param);
}

0x02 状态模式

1
2
1 理论基础
2 具体实现

1、理论基础
  状态模式的概念和有限状态机相似。最容易想到的状态机实现应该就是if else语句,实现起来类似这样:

1
2
3
4
5
6
7
8
9
10
if ("status1" == state) {
// do something
state = "status2";
} else if ("status2" == state) {
// do something
state = "status3";
} else if ("status3" == state) {
// do something
state = "status1";
}

  但是当状态变得很多,并且状态之间的耦合度变得很高时,这种代码就会很难维护。状态模式就是为了解决这个问题而产生的,一个最简单的状态模式,其UML图如下:

1.Context - 上下文。定义一个与使用者交互的接口。可以用该对象来记录当前状态。
2.State - 所有状态的父类。其虚函数定义状态之间发生转换时的行为。
3.ConcreteState - 继承自State的状态子类。有选择地实现State中定义的行为。

2、具体实现
  现在我们假设需要做一个状态机,其状态关系如下图:

  上下文 context.hpp:

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
#ifndef CONTEXT_H
#define CONTEXT_H

#include "state.h"

enum Action {
ACTION_CRIME,
ACTION_CORRECT,
ACTION_KILLED
};

class Context
{
public:
Context(State *state) : m_state(NULL) {
if (state)
setStatus(state);
}

~Context() { delete m_state; }

/* 设置状态 */
void setStatus(State* state) {
std::cout << "===== current status ===== " << state->name() << std::endl;

if (m_state)
delete m_state;
m_state = state;
m_state->set_context(this); // 传递上下文到状态中
}

/* 获取当前状态 */
State* getStatus() {
if (m_state)
return m_state;
}

/* 执行行为 */
void request_handle(Action action) {
switch (action) {
case ACTION_CRIME:
m_state->handle_crime();
break;
case ACTION_CORRECT:
m_state->handle_correct();
break;
case ACTION_KILLED:
m_state->handle_killed();
break;
default:
break;
}
}

private:
State* m_state; // 用于记录当前状态
};

#endif

  状态类头文件 state.h:

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
#ifndef STATE_H
#define STATE_H

#include <iostream>

class Context;

/* 状态父类 */
class State {
public:
void set_context(Context* context) { m_context = context; }

virtual std::string name() = 0;

virtual void handle_crime() {};
virtual void handle_correct() {};
virtual void handle_killed() {};

protected:
Context* m_context;
};

/* 平民状态 */
class ConcreteStateCommon : public State {
public:
std::string name() { return "common"; }

/* 犯罪行为 */
void handle_crime();
/* 枪毙行为 */
void handle_killed();
};

/* 假释犯状态 */
class ConcreteStateParolee : public State {
public:
std::string name() { return "parolee"; }

/* 犯罪行为 */
void handle_crime();
/* 劳改行为 */
void handle_correct();
/* 枪毙行为 */
void handle_killed();
};

/* 罪犯状态 */
class ConcreteStateKiller : public State {
public:
std::string name() { return "killer"; }

/* 劳改行为 */
void handle_correct();
/* 枪毙行为 */
void handle_killed();
};

/* 死人状态 */
class ConcreteStateDeath : public State {
public:
std::string name() { return "death"; }

void handle_crime() { std::cout << "Already death!" << std::endl; };
void handle_correct() { std::cout << "Already death!" << std::endl; };
void handle_killed() { std::cout << "Already death!" << std::endl; };
};

#endif

  状态类实现 state.cpp:

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
#include "context.hpp"
#include "state.h"
#include <iostream>

/* 平民状态 */
void ConcreteStateCommon::handle_crime() {
std::cout << "ConcreteStateCommon start crime.Become ConcreteStateKiller" << std::endl;
m_context->setStatus(new ConcreteStateKiller);
}

void ConcreteStateCommon::handle_killed() {
std::cout << "ConcreteStateCommon killed.Become ConcreteStateDeath" << std::endl;
m_context->setStatus(new ConcreteStateDeath);
}

/* 假释犯状态 */
void ConcreteStateParolee::handle_crime() {
std::cout << "ConcreteStateParolee start crime.Become ConcreteStateKiller" << std::endl;
m_context->setStatus(new ConcreteStateKiller);
}

void ConcreteStateParolee::handle_correct() {
std::cout << "ConcreteStateParolee start correct.Become ConcreteStateCommon" << std::endl;
m_context->setStatus(new ConcreteStateCommon);
}

void ConcreteStateParolee::handle_killed() {
std::cout << "ConcreteStateParolee killed.Become ConcreteStateDeath" << std::endl;
m_context->setStatus(new ConcreteStateDeath);
}

/* 罪犯状态 */
void ConcreteStateKiller::handle_correct() {
std::cout << "ConcreteStateKiller start correct.Become ConcreteStateParolee" << std::endl;
m_context->setStatus(new ConcreteStateParolee);
}

void ConcreteStateKiller::handle_killed() {
std::cout << "ConcreteStateKiller killed.Become ConcreteStateDeath" << std::endl;
m_context->setStatus(new ConcreteStateDeath);
}

  具体调用 main.cpp:

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
/*状态模式的实现.*/
/*
* 编译:g++ main.cpp state.h state.cpp context.hpp -o StatePattern
* 运行:./StatePattern
*/
#include "context.hpp"

int main() {
// 新建一个平民
Context *context = new Context(new ConcreteStateCommon);
// 平民犯罪,变成罪犯
context->request_handle(ACTION_CRIME);
// 罪犯劳改,变成假释犯
context->request_handle(ACTION_CORRECT);
// 假释犯枪毙,变死人
context->request_handle(ACTION_KILLED);
// 死人犯罪,不存在的
context->request_handle(ACTION_CRIME);

// 打印当前状态
std::cout << "Current Status: " << context->getStatus()->name() << std::endl;

delete context;
return 0;
}

0x03 引用文献

[1]https://baike.baidu.com/item/设计模式:可复用面向对象软件的基础/7600072
[2]https://www.runoob.com/design-pattern/design-pattern-intro.html

  • 计算机技术
DDos攻击
Rsync备份还原
  1. 1. 0x00 引言
  2. 2. 0x01 观察者模式
  3. 3. 0x02 状态模式
  4. 4. 0x03 引用文献
© 2023 JailbreakFox by Hexo
本站总访问量15666次
  • Articles
  • Change The World
  • About me

tag:

  • 计算机基础
  • 计算机技术
  • Linux 工具
  • 视觉,应用, AI
  • 工具
  • 计算机技术,Linux
  • 内核
  • Linux 计算机技术
  • 计算机技术 Linux
  • 计算机技术,Linux内核
  • 机器学习,神经网络,算法
  • Linux
  • 机器人
  • pytorch,神经网络,机器学习
  • 强化学习,算法
  • 计算机技术 黑客技术
  • 工具, 信息聚合
  • 数据库
  • 计算机技术,编译工具
  • 食物 茶
  • 工具,流
  • 游戏设计,游戏AI,入门
  • 信息安全技术
  • 配置
  • 视觉,入门
  • 数字货币 区块链
  • 远程桌面, 工具
  • 计算机技术,打包工具
  • 技巧

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 卞神
致力于创造风靡全球的机器人

迈向CyberPunk的新世界
Never STOP!