我很想听听您在操作期间使用什么技术来验证对象的内部状态,从它自己的角度来看,这些技术只会因为内部状态不好或不变的破坏而失败。
我的主要关注点是 C++,因为在 C# 中,官方和流行的方法是抛出异常,而在 C++ 中并没有唯一的方法可以做到这一点(好吧,在 C# 中也不是,我知道)。
请注意,我不是在谈论函数参数验证,而是更像是类不变完整性检查。
例如,假设我们想要一个Printer
对象Queue
异步打印作业。对于 的用户Printer
,该操作只能成功,因为异步队列结果在另一个时间到达。因此,没有相关的错误代码可以传达给调用者。
但是对于Printer
对象而言,如果内部状态不好,即类不变量被破坏,则此操作可能会失败,这基本上意味着:一个错误。该条件不一定对Printer
对象的用户有任何兴趣。
就个人而言,我倾向于混合三种内部状态验证风格,我无法真正决定哪一种是最好的,如果有的话,只能确定哪一种绝对是最差的。我想听听你对这些的看法,也想听听你在这件事上分享你自己的经验和想法。
我使用的第一种风格 - 以可控的方式失败比损坏数据更好:
void Printer::Queue(const PrintJob& job)
{
// Validate the state in both release and debug builds.
// Never proceed with the queuing in a bad state.
if(!IsValidState())
{
throw InvalidOperationException();
}
// Continue with queuing, parameter checking, etc.
// Internal state is guaranteed to be good.
}
我使用的第二种风格 - 比损坏的数据更好的崩溃无法控制:
void Printer::Queue(const PrintJob& job)
{
// Validate the state in debug builds only.
// Break into the debugger in debug builds.
// Always proceed with the queuing, also in a bad state.
DebugAssert(IsValidState());
// Continue with queuing, parameter checking, etc.
// Generally, behavior is now undefined, because of bad internal state.
// But, specifically, this often means an access violation when
// a NULL pointer is dereferenced, or something similar, and that crash will
// generate a dump file that can be used to find the error cause during
// testing before shipping the product.
}
我使用的第三种风格 - 比损坏的数据更好地静默和防御性地纾困:
void Printer::Queue(const PrintJob& job)
{
// Validate the state in both release and debug builds.
// Break into the debugger in debug builds.
// Never proceed with the queuing in a bad state.
// This object will likely never again succeed in queuing anything.
if(!IsValidState())
{
DebugBreak();
return;
}
// Continue with defenestration.
// Internal state is guaranteed to be good.
}
我对样式的评论:
- 我认为我更喜欢第二种风格,其中不隐藏故障,前提是访问冲突实际上会导致崩溃。
- 如果它不是不变量中涉及的 NULL 指针,那么我倾向于倾向于第一种样式。
- 我真的不喜欢第三种风格,因为它会隐藏很多错误,但我知道有人更喜欢在生产代码中使用它,因为它会产生一种不会崩溃的强大软件的错觉(功能只会停止运行,如损坏
Printer
对象上的排队)。
您更喜欢其中的任何一个,还是有其他方法可以实现这一目标?