17、备忘录(Memento)
概念:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
问题:在软件构建过程中,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到该对象的状态,便会暴露该对象的细节实现。
动机:如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。
总结:把一个对象的状态编码存到另一个稳定的对象中。
代码:
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
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento memento = orginator.createMomento();
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(memento);
}
18、组合模式(Composite)
概念:将对象组合成树结构以表示 ”部分-整体“ 的层次结构。Composite 使得用户对单个对象和组合对象的使用具有一致性(稳定)。
问题:在软件在某些情况下,客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。
动机:如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
总结:使用多态递归在节点内部根据其节点类型进行处理。
代码:
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
#include <iostream>
#include <list>
#include <string>
#include <algorithm>
using namespace std;
class Component
{
public:
virtual void process() = 0;
virtual ~Component(){}
};
//树节点
class Composite : public Component{
string name;
list<Component*> elements;
public:
Composite(const string & s) : name(s) {}
void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
}
void process(){
//1. process current node
//2. process child nodes
for (auto &e : elements)
e->process(); //多态调用
}
};
//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {}
void process(){
//process current node
}
};
void Invoke(Component & c){
//...
c.process();
//...
}
int main()
{
Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leat1("left1");
Leaf leat2("left2");
root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1);
root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2);
Invoke(root);
Invoke(leaf2);
Invoke(treeNode3);
}
19、迭代器(Iterator)
概念:提供一种方法顺序的访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示。
问题:在软件构件过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种 ”透明遍历” 也为 “同一种算法在多种集合对象上进行操作” 提供了可能。
动机:使用面向对象技术将这种遍历机制抽象为 “迭代器对象” 为 “应对变化中的集合对象“ 提供了一种优雅的方式。
总结:使用一个类维护一个对象的集合,使用多态进行元素操作。
代码:
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
// 下面是运行时多态,目前C++可以使用模板多态,效率更高。
template<typename T>
class Iterator
{
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual T& current() = 0;
};
template<typename T>
class MyCollection{
public:
Iterator<T> GetIterator(){
//...
}
};
template<typename T>
class CollectionIterator : public Iterator<T>{
MyCollection<T> mc;
public:
CollectionIterator(const MyCollection<T> & c): mc(c){ }
void first() override {
}
void next() override {
}
bool isDone() const override{
}
T& current() override{
}
};
void MyAlgorithm()
{
MyCollection<int> mc;
Iterator<int> iter= mc.GetIterator();
for (iter.first(); !iter.isDone(); iter.next()){
cout << iter.current() << endl;
}
}
20、职责链(Chain of Resposibility)
概念:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,知道有一个对象处理它为止。
问题:在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接收者,如果显式指定,将必不可少地带来请求发送者与接收者的紧耦合。
动机:如何使请求的发送者不需要指定具体的接收者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
总结:把处理请求的方式封装成一个个对象组成一个链,从头开始逐个判断该对象能否处理该请求。如果到链的末尾还没被处理应该设置一个缺省机制。
代码:
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;
enum class RequestType
{
REQ_HANDLER1,
REQ_HANDLER2,
REQ_HANDLER3
};
class Request
{
string description;
RequestType reqType;
public:
Request(const string & desc, RequestType type) : description(desc), reqType(type) {}
RequestType getReqType() const { return reqType; }
const string& getDescription() const { return description; }
};
class ChainHandler{
ChainHandler *nextChain;
void sendRequestToNextHandler(const Request & req)
{
if (nextChain != nullptr)
nextChain->handle(req);
}
protected:
virtual bool canHandleRequest(const Request & req) = 0;
virtual void processRequest(const Request & req) = 0;
public:
ChainHandler() { nextChain = nullptr; }
void setNextChain(ChainHandler *next) { nextChain = next; }
void handle(const Request & req)
{
if (canHandleRequest(req))
processRequest(req);
else
sendRequestToNextHandler(req);
}
};
class Handler1 : public ChainHandler{
protected:
bool canHandleRequest(const Request & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER1;
}
void processRequest(const Request & req) override
{
cout << "Handler1 is handle Request: " << req.getDescription() << endl;
}
};
class Handler2 : public ChainHandler{
protected:
bool canHandleRequest(const Request & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER2;
}
void processRequest(const Request & req) override
{
cout << "Handler2 is handle Request: " << req.getDescription() << endl;
}
};
class Handler3 : public ChainHandler{
protected:
bool canHandleRequest(const Request & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER3;
}
void processRequest(const Request & req) override
{
cout << "Handler3 is handle Request: " << req.getDescription() << endl;
}
};
int main(){
Handler1 h1;
Handler2 h2;
Handler3 h3;
h1.setNextChain(&h2);
h2.setNextChain(&h3);
Request req("process task ... ", RequestType::REQ_HANDLER3);
h1.handle(req);
return 0;
}