explorer

万丈高楼平地起,勿在浮沙筑高台

0%

[What] 职责链

学习视频:

从封装变化角度对模式分类:

  • 组件协作:通过 晚期绑定 ,来实现框架和应用之间的松耦合
    • Template Method
    • Strategy
    • Observer / Event
  • 单一职责
    • Decorator
    • Bridge
  • 对象创建
    • Factory Method
    • Abstract Factory
    • Prototype
    • Builder
  • 对象性能
    • Singleton
    • Flyweight
  • 接口隔离
    • Facade
    • Proxy
    • Mediator
    • Adapter
  • 状态变化
    • Memento
    • State
  • 数据结构
    • Composite
    • Iterator
    • Chain of Resposibility
  • 行为变化
    • Command
    • Visitor
  • 领域问题
    • Interpreter

问题

在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者。
如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合。

如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。

解决

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

Chain of Responsibility 模式的应用场合在于“一个请求可能有多个接收者,但是最后真正的接收者只有一个”, 这时候请求发送者与接收者的耦合有可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好地应对变化。

应用了 Chain of Responsibility 模式后,对象的职责分派将更具灵活性。我们可以在运行时动态添加/修改请求的处理职责。

如果请求传递到职责链的末尾仍然得不到处理,应该有一个合理的缺省机制。 这也是每个接受对象的责任,而不是发出请求的对象的责任。

按照 UML 类图的简易逻辑如下:

pic/chainOfRes.jpg

示例

先定义请求类

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
//file: request.h
#ifndef REQUEST_H
#define REQUEST_H

#include <string>

class Request
{
public:
typedef enum{
kHandle1,
kHandle2,
kHandle3,
}ReqType;

Request() = default;
Request(std::string &description, ReqType type = kHandle1);

const std::string &get_description(void);
ReqType get_type(void);
private:
std::string description_;
ReqType type_;
};

#endif // REQUEST_H



//file: request.cpp
#include "request.h"

Request::Request(std::string &description, ReqType type)
: description_(description), type_(type)
{

}
const std::string & Request::get_description(void)
{
return description_;
}
Request::ReqType Request::get_type(void)
{
return type_;
}

再定义处理基类:

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
//file: handle.h
#ifndef HANDLER_H
#define HANDLER_H

#include "request.h"

class Handler
{
public:
Handler(Handler *next = nullptr);

void process(Request &request);
protected:
virtual bool IsMyType(Request &request) = 0;
virtual void HandleType(Request &request) = 0;
private:
Handler *next_ = nullptr;
};

#endif // HANDLER_H


//file: handle.cpp
#include "handler.h"

#include <iostream>

Handler::Handler(Handler *next)
: next_(next)
{

}
void Handler::process(Request &request)
{
if(IsMyType(request)){
HandleType(request);
}
else{
if(next_){
std::cout << "switch to next node\n";
next_->process(request);
}
else{

}
}
}

然后是具体的处理类:

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
//file: concretehandlera.h
#ifndef CONCRETEHANDLERA_H
#define CONCRETEHANDLERA_H

#include "handler.h"

class ConcreteHandlerA : public Handler
{
public:
ConcreteHandlerA(Handler *next = nullptr);
protected:
bool IsMyType(Request &request) override;
void HandleType(Request &request) override;
};

#endif // CONCRETEHANDLERA_H

//file: concretehandlera.cpp
#include "concretehandlera.h"

#include <iostream>

ConcreteHandlerA::ConcreteHandlerA(Handler *next)
: Handler(next)
{

}
bool ConcreteHandlerA::IsMyType(Request &request)
{
std::cout << "ConcreteHandlerA type Check\n";
if(request.get_type() == Request::kHandle1)
{
return true;
}
return false;
}
void ConcreteHandlerA::HandleType(Request &request)
{
std::cout << "ConcreteHandlerA handle " << request.get_description() << std::endl;
}

//file: concretehandlerb.h
#ifndef CONRETEHANDLERB_H
#define CONRETEHANDLERB_H

#include "handler.h"

class ConcreteHandlerB : public Handler
{
public:
ConcreteHandlerB(Handler *next = nullptr);
protected:
bool IsMyType(Request &request) override;
void HandleType(Request &request) override;
};

#endif // CONRETEHANDLERB_H

//file: concretehandlerb.cpp
#include "conretehandlerb.h"

#include <iostream>

ConcreteHandlerB::ConcreteHandlerB(Handler *next)
: Handler(next)
{

}
bool ConcreteHandlerB::IsMyType(Request &request)
{
std::cout << "ConcreteHandlerB type Check\n";
if(request.get_type() == Request::kHandle2)
{
return true;
}
return false;
}
void ConcreteHandlerB::HandleType(Request &request)
{
std::cout << "ConcreteHandlerB handle " << request.get_description() << std::endl;
}

最后,使用者只需要发送消息即可

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
#include "concretehandlera.h"
#include "conretehandlerb.h"
#include "handler.h"
#include "request.h"

#include <iostream>
#include <string>

using namespace std;

int main()
{
cout << "Hello World!" << endl;

std::string str("test");
Request requst(str, Request::kHandle2);

ConcreteHandlerB handler_b;
ConcreteHandlerA handler_a(&handler_b);

Handler *handler = &handler_a;
handler->process(requst);



return 0;
}
Last Updated 2020-11-20 五 00:15.
Render by hexo-renderer-org with Emacs 26.3 (Org mode 9.4)