经典装饰器模式,装饰器本身是一种聚合aggregation。装饰器类和被装饰对象应该有共同接口(比如readwrite)。在实现这些接口的时候,应该调用被装饰对象的方法。

方法可以被装饰(Python常见),同时类也可以被装饰!

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
class DataSource {
public:
virtual ~DataSource() {}
virtual void writeData(std::string& data) const = 0;
virtual std::string readData() const = 0;
};

class FileDataSource: public DataSource {
public:
FileDataSource(std::string& filename) {
// get this file
}
void writeData(std::string& data) override {
// write data to file
}
std::string readData() override {
// read data from file
}
};

class DataSourceDecorator: public DataSource {
protected:
DataSource* wrappee;
public:
DataSourceDecorator(DataSource* datasource): wrappee(datasource) {
if (!datasource) {
throw std::invalid_argument("DataSource cannot be nullptr");
}
}
void writeData(std::string& data) override {
wrappee->writeData(data);
}
std::string readData() override {
return wrappee->readData(data);
}
virtual ~DataSourceDecorator() {
delete wrappee;
}
};

class EncryptionDecorator: public DataSourceDecorator {
void writeData(std::string& data) override {
// encrypt the data
std::string encryptedData = encrypt(data);
wrappee->writeData(encryptedData);
}
std::string readData() override {
// decrypt data
std::string data = wrappee->readData();
return decrypt(data);
}
};

class CompressionDecorator: public DataSourceDecorator {
void writeData(std::string& data) override {
// compress the data
std::string encryptedData = compress(data);
wrappee->writeData(encryptedData);
}
std::string readData() override {
// decompress data
std::string data = wrappee->readData();
return decompress(data);
}
};

int main(int argc, char* argv[]) {
FileDataSource* source = new FileDataSource("file.dat");
source->writeData("salary records");
source = new CompressionDecorator(source);
source->writeData("another salary records");
source = new EncryptionDecorator(source);
source->writeData("last salary records");
delete source;
return 0;
}