我有一个代表数据流的类,基本上
读取或写入文件,但首先要对数据进行加密/解密,并且还有一个底层的编解码器对象来处理要访问的媒体。
我正在尝试以RAII方式编写此类,并且我想要一个干净,美观,可用的设计。
令我困扰的是,现在构造函数中正在做很多工作。
在可以安全地使用对象的I/O例程之前,首先需要对编解码器进行初始化(这不是很苛刻的要求),但是随后要考虑 key 并初始化加密和其他内容-这些需要对以下内容进行一些分析:需要大量计算的媒体。
现在,我正在构造函数中执行所有这些操作,这需要花费很长时间。我正在考虑将加密初始化内容(大部分工作)从ctor移到一个单独的方法(例如Stream::auth(key)
)中,但是再一次,这将给类的用户带来一些责任,因为这是必需的在调用任何I/O操作之前运行auth()
。这也意味着我必须在I/O调用中进行检查,以验证是否已调用auth()
。
您认为什么是好的设计?
P.S.我确实读过类似的问题,但是我真的无法在这种情况下应用答案。它们大多就像“它会消失” ...:-/
谢谢
最佳答案
唯一真正坚不可摧的黄金法则是,在构造函数执行后,类必须处于有效,一致的状态。
您可以选择设计类,以使其在构造函数运行后处于某种“空”/“非事件”状态,也可以将其直接置于打算进入的“事件”状态。
通常,应该最好让构造函数构造您的类。通常,在真正可以使用某个类之前,您不会认为它是完全“构造的”,但是确实存在异常。
但是,请记住,在RAII中,关键思想之一是,除非该类准备就绪,初始化并可用,否则它不应该存在。这就是其析构函数进行清理的原因,也是其构造函数应进行设置的原因。
同样,确实存在异常(例如,某些RAII对象使您可以释放资源并及早执行清理,然后让析构函数不执行任何操作。)
因此,归根结底,这要视情况而定,您将不得不使用自己的判断力。
用不变性来考虑它。如果我得到了您的类(class)的实例,我可以依靠什么?我对它的把握越多,使用起来就越容易。如果它准备就绪可以使用,并且处于某种“已构建但尚未初始化”状态,并且可能处于“已清理但未销毁”状态,那么使用它很快就会变得很痛苦。
另一方面,如果它保证“如果对象存在,则可以按原样使用”,那么我将知道我可以使用它而不必担心之前对它做了什么。
听起来您的问题是您在构造函数中做的太多。
如果将工作分成多个较小的类怎么办?将编解码器分别初始化,然后我可以简单地将已初始化的编解码器传递给构造函数。所有的身份验证和密码学的东西以及诸如此类的东西也有可能被移到单独的对象中,一旦准备好就简单地传递给“此”构造函数。
然后,剩下的构造函数不必从头开始做所有事情,而可以从少数已经初始化并准备使用的辅助对象开始,因此只需要连接点即可。
关于c++ - 我的类的构造函数应执行多少工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8915873/