良好的程序设计/避免多重冗余检查的最佳实践(例如在C++中)

Good program design/best practice to avoid multiple redundant checks (eg. in C++)

本文关键字:C++ 最佳 检查 程序设计 冗余      更新时间:2023-10-16

假设我有一些函数(例如method1()method2()),并且只有在满足某些条件的情况下才能执行这些函数中的每一个(对于这个简单的例子,将其称为对布尔值的检查)。为了隔离条件检查,我将检查放在每个函数中,例如

void method1()
{
    if (bDoSomething) {
        doSomething1();
        doSomething2();
    }
}
void method2()
{
    if (bDoSomething) {
        doSomething1();
        doSomething3();
    }
}

然而,doSomethingN()函数也可以在method1()method2()之外单独调用,因此我将条件检查添加到每个doSomethingN()函数中,例如

void doSomething1() {
    if (bDoSomething) {
        doWork1();
    }
} 

此外,假设method1()method2()可以从同一个函数中调用,例如

void func1() {
    method1();
    method2();
}

这导致在调用func1()method1()method2()时对同一条件进行多次检查。有什么更好的方法可以避免多重检查?

关于如何最好地设计/构建程序以尽量减少这种事情,有什么好的资源吗?

取决于问题的具体细节。。您可以做的一件事是将检查放在doSomething函数中。

void doSomething1() {
    if(!bDoSomething) return;
    ....
} 

您不需要检查外部函数中的条件,只需调用适当的函数,它们就会在需要时执行。您仍然可以出于自我记录的目的保留它。

也有可能您的代码比需要的复杂得多。要进行诊断,您需要更多的细节和大局。

p.s您可以尝试我的检查风格,即如果为负数则返回,而不是如果为正数则处理,这有时可能会使代码更干净,但会降低缩进级别。

假设您有两个类:PrivateCaptain。让我们以Captain s命令Private s的方式使用它们。Captain s想要什么,Private s做什么

void Captain::HaveSomethingDone() {
   if(AmIAtAnAdvantage()) {
       for(Private& p : m_privates) {
           p.Attack();
       }
   }
   else if(IsSituationStalemate()) {
       for(Private& p : m_privates) {
           p.Hold();
       }
   }
   else if(IsALosingBattle()) {
       for(Private& p : m_privates) {
           p.Retreat();
       }
   }
}

在上面的例子中,Private无条件地做Captain想要的事情,因为Captain知道它在做什么。通过这种方式,我们可以清楚地分离关注点。

另一个,现在是方法。举个例子:

void DoSomething() {
    if(ShouldPrint()) {
        Print();
    }
    if(ShouldCleanUp()) {
        CleanUp();
    }
    // ...
}

在上面的例子中,DoSomething()知道它应该做什么。它是决定它应该做做什么的人。因此,Print()CleanUp()方法应该无条件地做它应该做的事情。Print()打印。CleanUp()清理。

现在想想。

我认为避免多重条件检查的最佳方法是在代码中实现State设计模式。这种设计模式只允许您将代码用作状态机,这意味着根据对象状态的状态,您可以调用所需的方法。你可以在这里获得更多信息http://en.wikipedia.org/wiki/State_pattern

好吧,我想你的检查很重,否则我不会担心双重调用,因为你的代码会更干净。

我心里有两件事:

  • 将第一个检查结果缓存在类中的某个位置。

  • 生成调用者对象,只有当您的条件为true时才能创建该对象。

类似的东西:

class ConditionalCaller
{
public:
    void Method1();
    void Method2();
};
class YourClass
{
public:
    ConditionalCaller* GetCaller()
    {
        if (CanGetCaller())
            return new ConditionalCaller();
        return NULL;
    }
    bool CanGetCaller();
};

有几种不同的情况:

  1. method1method2是私有的,您可以控制它们在哪里被调用,并且您可以保证检查所有预条件。在这种情况下,您可以在这些方法中避免这些测试
  2. method1method2是公共的,您记录了必须满足几个条件(如std中的容器)作为先决条件
  3. method1method2检查它们的前提条件并相应地响应(抛出和异常,什么都不做…)
  4. 您可以创建方法的已检查和未检查版本(混合其他变体),并通过不同的名称*_checked或其他参数(如notthrow-new)来区分它们

但请记住Scott Meyers:使界面易于正确使用,难以错误使用。

因此,您必须做出决定并将其记录下来。