我有兴趣听到什么样的技术(s)你在使用验证的内部状态的一个目的操作过程中,从它自己的观点,只能失败,因为不良的内部状态或固定不变的违反。

我的主要重点是在C++的,因为在C#官方和普遍的方法是扔一个例外,并在C++有不只一个 的方式来做到这一点(ok,不是真的在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.
}

我的评论的方式:

  1. 我想我更喜欢第二风格,那里的失败不是隐藏的,提供了一个访问冲突实际上导致崩溃。
  2. 如果它不是一个空的指针所涉及的不变的,那么我往往倾向于第一个风格。
  3. 我真的不喜欢的三样式,因为它隐藏大量的错误,但我知道人们喜欢它在生产码,因为它造成一种错觉的一个功能强大的软件,不会崩溃(功能只会停止功能,如在排队上打破 Printer 对象)。

你喜欢任何这些或者你有其他的方式实现这个吗?

有帮助吗?

解决方案

这个问题最好是考虑在结合有怎么你的测试你的软件。

重要的是打破不变的测试期间提交的作为一个较严重的错误,只是作为一个崩溃。建立用于测试在发展期间可以停止死亡和输出诊断。

它可适当添加码的防御性的,而不是像你的风格3:你的 DebugBreak 要转储的诊断测试版本,但只是一个突破点的开发。这使得不可能的情况下,开发是防止工作中的错误无关联的代码。

可悲的是,我经常看到这样做的其他方面,开发人员得到的所有不便,但是,测试建立航行通过打破不变量。很多奇怪的行为错误得到申请,其中实际上在一个单一的错误是原因。

其他提示

你可以使用一种称为NVI(非虚拟的接口)一起 template method 模式。这可能是我怎么会这样做(当然,这只是我个人的意见,这确实是值得商榷):

class Printer {
public:
    // checks invariant, and calls the actual queuing
    void Queue(const PrintJob&);
private:
    virtual void DoQueue(const PringJob&);
};


void Printer::Queue(const PrintJob& job) // not virtual
{
    // Validate the state in both release and debug builds.
    // Never proceed with the queuing in a bad state.
    if(!IsValidState()) {
        throw std::logic_error("Printer not ready");
    }

    // call virtual method DoQueue which does the job
    DoQueue(job);
}

void Printer::DoQueue(const PrintJob& job) // virtual
{
    // Do the actual Queuing. State is guaranteed to be valid.
}

Queue 是非虚拟的,不变的是,仍然检查,如果一个源类复盖 DoQueue 对特殊处理。


为你的选择:我认为它取决于条件你想要的检查。

如果它是一个内部不变

如果这是一个不变的,它不应该 可能用户的类 违反它。该类应该关心 关于其固定不变本身。为此, 我 assert(CheckInvariant()); 在 这样的情况。

它仅仅是一个先决条件的方法

如果它仅仅是一个先决条件, 类的用户会 保证(说,只有印刷之后 打印机的准备),我要扔 std::logic_error 如上所示。

我真的会阻止从检查的一个条件,但后来做什么。


类的用户可以本身的断言之前呼吁的方法,预先的条件,它是满意的。所以一般来说,如果一类是负责一些国家,并找到一个国家是无效的,就应该断言。如果此类发现的一个条件受到侵犯,不属于它的责任,它应该扔掉。

这是一个细和非常有关的问题。恕我直言,任何应用程序的架构应该提供一项战略,以报告打破不变量。一个可以决定使用例外,使用'错误登记册'的对象,或者有明确的检查结果的任何行动。也许甚至还有其他的策略-那不是重点。

根据一个可能大声的崩溃就是一个糟糕的想法:你无法保证应用程序将崩溃,如果你不知道的原因不变的违反。在这种情况下不,你还有腐败的数据。

确定其接口 解决方案,从litb是一个整洁的方式来检查不变量。

棘手的问题,这个:)

就个人而言,我倾向于只是扔一个例外,因为我通常太过到我在做什么当实现的东西来照顾应该是什么照顾你的设计。这通常回来咬我以后...

我的个人经验"做的一些记录-和-然后-不要-不要-什么-更多"-的战略是,它也回来咬你-尤其是如果它是实现喜欢你的情况(没有全球战略,每一类可能这样做的方式不同).

我会做什么,只要我发现了一个问题,这样,将发言的我的团队并告诉他们,我们需要某种形式的全球错误的处理。什么样的处理将不取决于你的产品(你不想只是做什么和记录的东西在一个微妙的开发志同道合的文件在空中交通管制系统,但它会工作的现如果你是一个驱动程序,也就是说,一个打印机)).

我猜我要说的是,恕我直言,这个问题是有些东西你应该解决对一个设计水平的应用程序而不是在执行水平。-而且可悲的是有没有神奇的解决方案:(

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top