0%

设计模式之装饰模式

设计模式基础(4):装饰模式

介绍装饰模式的C++示例代码、面向的问题、图解装饰模式核心思想

面向的需求

处理“过度地使用继承来扩展对象功能”。因为继承为类型引入了更多的静态特质,使得拓展方式缺乏灵活性,并且随着子类的增多,数量急剧扩张。

如何拓展对象的功能,并具有很大的动态性,以便于程序的后期维护。

示例代码

采用继承手段来拓展功能

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//业务操作
class Stream{
public
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;

virtual ~Stream(){}
};

//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}

};

class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}

};

class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}

};

//扩展操作
class CryptoFileStream :public FileStream{
public:
virtual char Read(int number){

//额外的加密操作...
FileStream::Read(number);//读文件流

}
virtual void Seek(int position){
//额外的加密操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
}
};

class CryptoNetworkStream : :public NetworkStream{
public:
virtual char Read(int number){

//额外的加密操作...
NetworkStream::Read(number);//读网络流
}
virtual void Seek(int position){
//额外的加密操作...
NetworkStream::Seek(position);//定位网络流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
NetworkStream::Write(data);//写网络流
//额外的加密操作...
}
};

class CryptoMemoryStream : public MemoryStream{
public:
virtual char Read(int number){

//额外的加密操作...
MemoryStream::Read(number);//读内存流
}
virtual void Seek(int position){
//额外的加密操作...
MemoryStream::Seek(position);//定位内存流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
MemoryStream::Write(data);//写内存流
//额外的加密操作...
}
};

class BufferedFileStream : public FileStream{
//...
};

class BufferedNetworkStream : public NetworkStream{
//...
};

class BufferedMemoryStream : public MemoryStream{
//...
}

class CryptoBufferedFileStream :public FileStream{
public:
virtual char Read(int number){

//额外的加密操作...
//额外的缓冲操作...
FileStream::Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Seek(position);//定位文件流
//额外的加密操作...
//额外的缓冲操作...
}
virtual void Write(byte data){
//额外的加密操作...
//额外的缓冲操作...
FileStream::Write(data);//写文件流
//额外的加密操作...
//额外的缓冲操作...
}
};

void Process(){

//编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();

BufferedFileStream *fs2 = new BufferedFileStream();

CryptoBufferedFileStream *fs3 =new CryptoBufferedFileStream();

}

利用装饰模式重构代码

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
//业务操作
class Stream{

public
virtual char Read(int number)=0;
virtual void Seek(int position)=0;
virtual void Write(char data)=0;

virtual ~Stream(){}
};

//主体类
class FileStream: public Stream{
public:
virtual char Read(int number){
//读文件流
}
virtual void Seek(int position){
//定位文件流
}
virtual void Write(char data){
//写文件流
}

};

class NetworkStream :public Stream{
public:
virtual char Read(int number){
//读网络流
}
virtual void Seek(int position){
//定位网络流
}
virtual void Write(char data){
//写网络流
}

};

class MemoryStream :public Stream{
public:
virtual char Read(int number){
//读内存流
}
virtual void Seek(int position){
//定位内存流
}
virtual void Write(char data){
//写内存流
}

};

//扩展操作
DecoratorStream: public Stream{
protected:
Stream* stream;//...

DecoratorStream(Stream * stm):stream(stm){

}

};

class CryptoStream: public DecoratorStream {


public:
CryptoStream(Stream* stm):DecoratorStream(stm){

}


virtual char Read(int number){

//额外的加密操作...
stream->Read(number);//读文件流
}
virtual void Seek(int position){
//额外的加密操作...
stream::Seek(position);//定位文件流
//额外的加密操作...
}
virtual void Write(byte data){
//额外的加密操作...
stream::Write(data);//写文件流
//额外的加密操作...
}
};

class BufferedStream : public DecoratorStream{

public:
BufferedStream(Stream* stm):DecoratorStream(stm){

}
//...
};

void Process(){
//运行时装配
FileStream* s1=new FileStream();
CryptoStream* s2=new CryptoStream(s1);
BufferedStream* s3=new BufferedStream(s1);
BufferedStream* s4=new BufferedStream(s2);
}

代码分析和思想

单纯继承下类的关系

原始类

采用装饰模式下类的关系

重构类

核心思想

  • 要为原有的类拓展新功能。有时要注意到其实我们是在为某一抽象类增加功能,而不要贸贸然地去为某一个具体的类采用继承的方式。可能会导致类的种类过多,代码维护不方便。
  • 通过组合的关系为某一个对象增加额外的职责,要更为灵活。

装饰模式类图关系

结构图
要注意到,装饰类既继承了基类,又在内部维护了一个基类对象(组合)。这是十分显著的特征。

关键点

  • 技法上,采用组合的方式来拓展功能。
  • 目标上,为了解决主体类在多个方向上扩展的功能,如何更好的动态拓展功能。