我有兴趣听到在操作期间使用什么技术来验证对象的内部状态,从操作本身的角度来看,由于内部状态不良或不变的违反,只能失败。因为在C#中,官方和普遍的方式是抛出一个异常,并且在C++中不仅有一个单一的方法来做到这一点(好吧,不是真的在C#中,我知道那)。你如何验证对象的内部状态?
请注意,我是而不是谈论函数参数验证,但更像是类不变完整性检查。
例如,假设我们想要一个Printer
对象异步到打印作业Queue
。对于Printer
的用户,该操作只能成功,因为异步队列结果与另一次到达。所以,没有相关的错误代码传达给调用者。
但是对于Printer
对象,如果内部状态不好,即该类不变被打破,这个操作可能会失败,这基本上意味着:一个错误。该条件对于Printer
对象的用户不一定感兴趣。我个人倾向于将三种风格的内部状态验证混合在一起,并且我不能真正确定哪一个最好(如果有的话)只有哪一个绝对是最差的。我希望听到您对这些问题的看法,以及您在这个问题上分享您的任何经验和想法。
的第一个样式我用 - 比数据损坏可控的方式更好地失败 - :
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.
// 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 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.
}
我的commen ts的风格:
- 我想我更喜欢第二种风格,其中失败不隐藏,只要访问冲突实际上导致崩溃。
- 如果它不是一个NULL指针参与不变量,那么我倾向于倾向于第一种风格。
- 我真的不喜欢第三种风格,因为它会隐藏大量的错误,但我知道那些喜欢生产代码的人,因为它创造了一个强大的软件的幻觉,它不会崩溃(功能将停止运行,如在破碎的
Printer
对象上排队)。
你更喜欢这些吗?还是你有其他方法来实现这个目标?
我实际上并不同意NVI是一个很好的解决方案,在我所述的具体情况下,如果Printer是基类,但是之前添加了接线明显的需求往往是徒劳的,如果我看到需要从Printer中派生出来,那么当时我会重构。 – 2008-12-18 10:28:57