我有以下类(class):
class Stream {};
class FileStream : public Stream {};
class NetworkStream : public Stream {};
每个类都有一个write()
方法(虚拟的)。
我可以在两种类型的媒体上使用 FileStream:HDD 和 SSD。如果我正在写入 HDD,我不会对 FileStream
已经提供的内容做任何特别的事情。但是,如果我正在编写 SSD,则在调用 write()
之前我需要执行一些逻辑。在 FileStream
中,我不知道我要写入的媒体是什么。只有调用站点知道。我想在这里使用 decorator,但 decorator 旨在与所有流一起使用。我只想在某些情况下扩展 NetworkStream
的功能。某种形式的装饰器在这里合适吗?如果不是,我应该使用什么设计模式?如果我们假设 FileStream::write()
只是将整个内部缓冲区刷新到文件并将其保存到磁盘,那么装饰器将需要在写入流之前将一些元数据写入流。
我想创建一个不使用继承的简单装饰器类:
class FileStreamDecorator
{
public:
FileStreamDecorator( FileStream& stream ) : m_stream( stream ) {}
void write() {
m_stream << "Some Metadata";
m_stream.write();
}
private:
FileStream& m_stream;
};
它会像这样使用:
FileStream stream;
stream << "Complete file data";
// At this point we know we are writing to SSD, so we must use the decorator
FileStreamDecorator decorator( stream );
decorator.write();
这是一个合适的解决方案吗?谁能想到更好的方法?
最佳答案
Would this be an appropriate solution? Can anyone think of a better way?
没有。您正在创建一个装饰器类,并依赖客户端代码在需要时不要忘记使用它。
如果客户端代码忘记执行额外的步骤,代码看起来没问题(客户端代码中没有任何建议应该在那里初始化装饰器)。
在一个月(或就此而言五年)内,您将忘记这一点,或者转移到其他项目,维护该项目的人将不得不意识到需要在客户端中初始化一个新对象。
最好使用 SSDFileStream 特化,它会覆盖基类的 write()(默认行为),在内部调用基类版本,然后执行任何额外的步骤。
我能想到的最佳实现:
class FileStream {
virtual void write();
};
class SSDFileStream: public FileStream {
virtual void write() {
FileStream::write();
write_ssd();
}
protected:
void write_ssd();
};
此外,您可以将 FileStream 抽象化,并添加 HDDFileStream 特化。如果 HDDFileStream 检测到它正在 SSD 上写入,它可能会抛出异常。如果您要求它在 HDD 路径上写入,SSDFileStream 可能会做同样的事情。
这将使客户端代码易于正确编写,并且不可能“*”编写错误。
'* 编写错误/不稳定/脆弱/丑陋的代码从来都不是不可能的,但您仍然可以让它难以实现。
关于c++ - 特定子类的装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16195493/