我们打算做一些IO操作,设计一些关于流的库.
#include
class Stream { // 基类:定义流的一些基本操作
public:
virtual char Read(int number) = 0; // 纯虚函数
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}; // 养成良好的习惯,基类析构函数写成虚函数
};
// 主体类:文件流操作,继承自Stream
class FileStream : public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取文件流
virtual void Seek(int position){/* code... */ } // 定位文件流
virtual void Write(char data) {/* code... */ } // 写入文件流
};
// 主体类:网络流操作,继承自Stream
class NetworkStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取网络流
virtual void Seek(int position) {/* code... */ } // 定位网络流
virtual void Write(char data) {/* code... */ } // 写入网络流
};
// 主体类:内存流操作,继承自Stream
class MemoryStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取内存流
virtual void Seek(int position) {/* code... */ } // 定位内存流
virtual void Write(char data) {/* code... */ } // 写入内存流
};
// 现在考虑扩展操作,如果我们要对文件流进行加密
class CryptoFileStream :public FileStream {
public:
virtual char Read(int number) { // 读取文件流
// 额外的加密操作
FileStream::Read(number);
}
virtual void Seek(int position) { // 定位文件流
// 额外的加密操作
FileStream::Seek(position);
}
virtual void Write(char 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(char 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(char data) { // 写入内存流
// 额外的加密操作
MemoryStream::Write(data);
}
};
// 继续对FileStream进行扩展
class BufferedFileStream:public FileStream{ /* 额外的缓冲操作*/ };
// 对文件既有缓冲扩展又有加密扩展
class CryptoBufferedFileStream :public FileStream { // 当然也可继承自BufferedFileStream
// 额外的缓冲操作
// 额外的加密操作
};
int main()
{
// 使用设计模式前,发生的是编译时装配
CryptoFileStream *fs1 = new CryptoFileStream();
BufferedFileStream *fs2 = new BufferedFileStream();
CryptoBufferedFileStream *fs3 = new CryptoBufferedFileStream();
/*codes to do something... */
delete fs3;
delete fs2;
delete fs1;
renturn 0;
}
使用设计模式前,代码结构关系如下:
Stream
||
FileStream NetworkStream MemoryStream
|| || ||
CryptoFileStream CryptoNetworkStream CryptoMemoryStream
BufferedFileStream BufferedNetworkStream BufferedMemoryStream
CryptoBufferedFileStream CryptoBufferedNetworkStream CryptoBufferedMemoryStream
假设扩展类型数量为N,操作种类为M,则在谁用设计模式前,类的总量为O(MN),当M/N数量较多时,类数量是很大的;另一方面,我们发现类代码里有很多重复冗余的操作.
我们是否能够把O(MN) 变为O(M+N)?在OOP设计原则里,提到,能够使用组合的方式我们尽量不适用继承,使用组合方式后是否能讲类数量变为O(M+N)?
#include
class Stream { // 基类:定义流的一些基本操作
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}; // 养成良好的习惯,基类析构函数写成虚函数
};
// 主体类:文件流操作,继承自Stream
class FileStream : public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取文件流
virtual void Seek(int position){/* code... */ } // 定位文件流
virtual void Write(char data) {/* code... */ } // 写入文件流
};
// 主体类:网络流操作,继承自Stream
class NetworkStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取网络流
virtual void Seek(int position) {/* code... */ } // 定位网络流
virtual void Write(char data) {/* code... */ } // 写入网络流
};
// 主体类:内存流操作,继承自Stream
class MemoryStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取内存流
virtual void Seek(int position) {/* code... */ } // 定位内存流
virtual void Write(char data) {/* code... */ } // 写入内存流
};
class CryptoStream{
public:
CryptoStream(Stream* stream) { this->m_stream = stream; }
public:
virtual char Read(int number) {
doCrypto();
m_stream->Read(number);
}
virtual void Seek(int position) {
doCrypto();
m_stream->Seek(position);
}
virtual void Write(char data) {
doCrypto();
m_stream->Write(data);
}
private:
void doCrypto() {}
private:
Stream* m_stream; // 编译时无关,运行时根据new的具体对象决定调用什么方法
};
class BufferedStream{
public:
BufferedStream(Stream* stream){ this->m_stream = stream; }
public:
virtual char Read(int number) {
doBuffered();
m_stream->Read(number);
}
virtual void Seek(int position) {
doBuffered();
m_stream->Seek(position);
}
virtual void Write(char data) {
doBuffered();
m_stream->Write(data);
}
private:
void doBuffered() {}
private:
Stream* m_stream; // 编译时无关,运行时根据new的具体对象决定调用什么方法
};
int main()
{
// 使用设计模式后,类的数量变为加法关系,而不再是乘法关系(CryptoStream,BufferedStream)
Stream *s1 = new FileStream();
CryptoStream *s2 = new CryptoStream(s1);
BufferedStream *s3 = new BufferedStream(s1);
/*codes to do something... */
delete s1; delete s2; delete s3;
renturn 0;
}
使用设计模式后,类的数量变为加法关系,而非乘法关系(CryptoStream,BufferedStream).
如何实现既加密、又缓存?
#include
class Stream { // 基类:定义流的一些基本操作
public:
virtual char Read(int number) = 0;
virtual void Seek(int position) = 0;
virtual void Write(char data) = 0;
virtual ~Stream() {}; // 养成良好的习惯,基类析构函数写成虚函数
};
// 主体类:文件流操作,继承自Stream
class FileStream : public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取文件流
virtual void Seek(int position){/* code... */ } // 定位文件流
virtual void Write(char data) {/* code... */ } // 写入文件流
};
// 主体类:网络流操作,继承自Stream
class NetworkStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取网络流
virtual void Seek(int position) {/* code... */ } // 定位网络流
virtual void Write(char data) {/* code... */ } // 写入网络流
};
// 主体类:内存流操作,继承自Stream
class MemoryStream :public Stream {
public:
virtual char Read(int number) {/* code... */ } // 读取内存流
virtual void Seek(int position) {/* code... */ } // 定位内存流
virtual void Write(char data) {/* code... */ } // 写入内存流
};
class CryptoStream:public Stream{
public:
CryptoStream(Stream* stream) { this->m_stream = stream; }
public:
virtual char Read(int number) {
doCrypto();
m_stream->Read(number);
}
virtual void Seek(int position) {
doCrypto();
m_stream->Seek(position);
}
virtual void Write(char data) {
doCrypto();
m_stream->Write(data);
}
private:
void doCrypto() {}
private:
Stream* m_stream; // 编译时无关,运行时根据new的具体对象决定调用什么方法
};
class BufferedStream:public Stream {
public:
BufferedStream(Stream* stream){ this->m_stream = stream; }
public:
virtual char Read(int number) {
doBuffered();
m_stream->Read(number);
}
virtual void Seek(int position) {
doBuffered();
m_stream->Seek(position);
}
virtual void Write(char data) {
doBuffered();
m_stream->Write(data);
}
private:
void doBuffered() {}
private:
Stream* m_stream; // 编译时无关,运行时根据new的具体对象决定调用什么方法
};
int main()
{
// 运行时装配
Stream *m1 = new FileStream();
CryptoStream *m2 = new CryptoStream(m1);
BufferedStream *m3 = new BufferedStream(m2); // m3既可以加密,又可以缓存
delete s1; delete s2; delete s3;
/*codes to do something... */
delete s1; delete s2; delete s3;
renturn 0;
}
CryptoStream和BufferedStream含有公共的部分m_stream,根据GOF的思想,含有的公共部分可以网上提,即可以将 Stream* m_stream 放在基类里,但是我们发现FileStream、NetworkStream、MemoryStream并不需要这个.由此,我们可以写个中间类,比如MidStream,如文中代码所述;此时,可以CryptoStream和BufferedStream让继承MidStream即可.
// 创建中间类,这里不做虚函数实现,也就无法创建对象
class MidStream:public Stream {
protected:
Stream *m_stream;
};