将 if 语句中的逻辑重构到最低限度

Refactoring logic inside if statement to bare minimum

前段时间我用 SVG 编写了一个教育 JavaScript 应用程序(公司闭源 )。该应用程序的最基本形式由两列(左和右)组成,每列包含各种几何形状(正方形、三角形、圆形等)

一列中的每个几何形状都可以连接(通过画一条线)到相对列中的另一个几何形状。但是,任一列中的形状都可以有一个或多个连接 to/from,具体取决于其设置。

因此设置为 {multiple: false} 的形状只能与它或从它有一个连接。连接是来自它还是来自另一个形状都无关紧要;一个连接意味着只有一个连接,无论来源如何。

通过画线连接形状的代码部分是一个过于复杂的 if 语句。这是:

if ((!sourceHasLines && !targetHasLines) ||
  (sourceHasLines && sourceCanMultiply && !targetHasLines) ||
  (sourceHasLines && sourceCanMultiply && targetHasLines && targetCanMultiply) ||
  (!sourceHasLines && !sourceCanMultiply && targetHasLines && targetCanMultiply) || 
  (!sourceHasLines && sourceCanMultiply && targetHasLines && targetCanMultiply)) {
    // Create a line only if one of the above comparisons succeeds
    connection = self.connect($source, $target);
}

现在看代码,感觉if语句里面的逻辑大概可以压缩下来,心里也有了一些想法。但是,我觉得这与排列或其他一些 CS 相关的逻辑(如离散数学)有关。我主要是自学成才,所以我想看看有人会如何处理这个问题并重构上面的 if 语句。

请注意,代码运行良好,但我想知道如何改进它。这是具有 top/bottom 行而不是 left/right 列的原型的屏幕截图:

怎么样:

if ((!SL || SM) && (!TL || TM)) ...

即:源必须为空或多行,目标必须为空或多行

看看这两行

(!sourceHasLines && !sourceCanMultiply && targetHasLines && targetCanMultiply)

(!sourceHasLines && sourceCanMultiply && targetHasLines && targetCanMultiply)

如果其中任何一个为真,我们将画一条线

让我们

a = source has lines
A = source can multiply
b = target has lines
B = target can multiply

以上两行变为

(1) ~a AND ~ A AND b AND B
(2) ~a AND A AND b AND B

我们使用 (1)AND(2) 进行决策,这使得 A(源可以相乘)当源没有行时不要关心。

因此这两行可以替换为

(!sourceHasLines && targetHasLines && targetCanMultiply)

现在你的代码变成了

if ((!sourceHasLines && !targetHasLines)
    || (sourceHasLines && sourceCanMultiply && !targetHasLines) 
    || (sourceHasLines && sourceCanMultiply && targetHasLines && targetCanMultiply) 
    || (!sourceHasLines && targetHasLines && targetCanMultiply)) {    
    connection = self.connect($source, $target);
}

可以进一步简化为

if ((!sourceHasLines || sourceCanMultiply) && (!targetHasLines || targetCanMultiply )) {    
    connection = self.connect($source, $target);
}

您可以应用代数来减少代码的逻辑:

假设:

A = sourceHasLines;
B = targetHasLines;
C = sourceCanMultiply;
D = targetCanMultiply;

它将翻译成:

if ((!A && !B) ||
  (A && C && !B) ||
  (A && C && B && D) ||
  (!A && !C && B && D) || 
  (!A && C && B && D)) {
    // Create a line only if one of the above comparisons succeeds
    connection = self.connect($source, $target);
}

这将使用代数翻译成:

(!A * !B) + ( A * C * !B ) + ( A * C * B * D) + ( !A * !C * B * D ) + ( !A * C * B * D )

应用一些数学:

!A * ( !B + ( B * D ) ) + A * C * ( !B + ( B * D ) )

( !B + ( B * D ) ) * ( !A + ( A * C ) ) 

(!A + C) * ( !B + D)

因此:

if(!sourceHasLines || sourceCanMultiply) && ( !targetHasLines || targetCanMultiply)) {
    connection = self.connect($source, $target);
}