将 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);
}
- 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);
}
前段时间我用 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);
}
- 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);
}