什么是使用众多布尔开关的替代方案

时间:2017-10-12 18:46:00

标签: java java-8 theory

我有一个旧代码需要恢复生命,它使用大约10-15个布尔人在整个班级中跳舞,如下:

if (condition)
{
  bool1 = true
}
if (condition)
{
  bool2 = true
}
...

然后

if (bool1 == true && bool2 == true && bool3 == false)
{
  do something
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
  do something
}
...

可以避免以这种方式编码吗?有没有更好的方法来实现这一点?也许利用地图?

我希望提高可读性和整体性能,因为这段代码长达1,000多行。

反馈后添加更具体的例子:

boolean bool1 = false, bool2 = false, bool3 = false, bool4 = false, bool5 = false,
bool6 = false, bool7 = false, bool8 = false, bool9 = false, bool10 = false;

if (string_object.startsWith("Pattern1"))
{
    bool1 = true
}
if (string_object.startsWith("Pattern2")
{
    bool2 = true
}
if (string_object.startsWith("Pattern3")
{
    bool3 = true
}
if (string_object.startsWith("Pattern4")
{
    bool4 = true
}
if (string_object.startsWith("Pattern5")
{
    bool5 = true
}
// and so on...

if (system_type.equals("type1"))
{
    if (bool1 == true && bool2 == true && bool3 == false)
    {
        system_value.set("value1")
    }
    else if (bool1 == true && bool2 == false && bool3 == false)
    {
        system_value.set("value2")
    }
    else if (bool1 == true && bool3 == false && bool4 == true)
    {
        system_value.set("value3")
    }
}
else if (system_type.equals("type2"))
{
    if (bool1 == true && bool2 == true && bool4 == true)
    {
        system_value.set("value1")
    }
    else if (bool1 == true && bool3 == false && bool5 == true)
    {
        system_value.set("value4")
    }
    else if (bool1 == true && bool3 == false && bool4 == true)
    {
        system_value.set("value5")
    }
}
// and so on...

5 个答案:

答案 0 :(得分:4)

你可以做一些事情。

  1. 正如其他人所提到的,代码如下:

    if(condition) {   bool1 = true; }

  2. 可以压缩为:

    bool1 = (condition);
    
    1. 另一个有用的工具是Martin Fowler的重构工具之一 - Decompose Conditional
    2. 这方面的一个例子就是改变这个:

      if (bool1 == true && bool2 == true && bool3 == false)
      {
        do something
      }
      else if (bool1 == true && bool2 == false && bool3 == false)
      {
        do something
      }
      

      对于这样的事情:

      if (firstCondition())
      {
        do something
      }
      else if (secondCondition())
      {
        do something
      }
      
      private boolean firstCondition() {
        return (bool1 && bool2 && !bool3 );
      }
      
      private boolean secondCondition() {
        return (bool1 && !bool2 && !bool3);
      }
      

      分解这样的复杂条件使您的代码更易于阅读和维护。

答案 1 :(得分:1)

您可以从布尔值构造位图,并将所需组合编码为整数。

以下是一个例子:让我们说你需要三个布尔值,flag0flag1flag2,你需要检查五种不同的旗帜组合:

flag2 flag1 flag0   Action
----- ----- ----- ----------
 true false false ActionOne
 true  true false ActionTwo
 true false  true ActionThree
false false  true ActionFour
false  true  true ActionFive

然后你可以按如下方式构建标志:

int flags = 0;
if (condition0) flags |= (1 << 0);
if (condition1) flags |= (1 << 1);
if (condition2) flags |= (1 << 2);

现在,每个条件组合都被编码为0到7之间的唯一数字,包括0和7,因此可以使用switch语句进行检查:

switch(flags) {
    case 4: actionOne();   break; // 1 0 0
    case 6: actionTwo();   break; // 1 1 0
    case 5: actionThree(); break; // 1 0 1
    case 1: actionFour();  break; // 0 0 1
    case 3: actionFive();  break; // 0 1 1
}

答案 2 :(得分:1)

大多数情况下,这种反模式是由于开发人员不希望仅为一个新行为创建子类。如果是这种情况,多态可能有所帮助。

假设您有以下课程:

public class Animal {
  private final boolean isCat;
  private final boolean isReptile;
  private final boolean isDog;


  private Animal(final boolean isCat, final boolean isReptile, final boolean isDog) {
    this.isCat = isCat;
    this.isReptile = isReptile;
    this.isDog = isDog;
  }

  public static Animal getLizard() {
    return new Animal(false, true, true);
  }

  public static Animal getDog() {
    return new Animal(false, false, false);
  }

  public String seeStranger() {
    final StringBuilder result = new StringBuilder(this.toString());
    if (isDog) {
      result.append(" barks and");
    } else if (isCat) {
      result.append(" meows and");
    }
    if (isReptile) {
      result.append(" crawls away.");
    } else {
      result.append(" walks forward.");
    }
    return result.toString();
  }
}

您真正想要的是具有不同行为的多个类:

public abstract class Animal {


  public static Animal getLizard() {
    return new Lizard();
  }

  public static Animal getDog() {
    return new Dog();
  }

  public abstract String seeStranger();

  private static class Lizard extends Animal {
    @Override
    public String seeStranger() {
      return this.toString() + " crawls away.";
    }
  }

  private static class Dog extends Animal {
    @Override
    public String seeStranger() {
      return this.toString() + " barks and walks forward.";
    }
  }
}

答案 3 :(得分:1)

根据您的使用情况,您可能会发现更容易完全省略布尔变量,只是将条件内联在控制流语句中。例如,您可以更改此内容:

if (condition1)
{
  bool1 = true
}
else if (condition2)
{
  bool2 = true
}

...

if (bool1 == true && bool2 == true && bool3 == false)
{
  do something
}
else if (bool1 == true && bool2 == false && bool3 == false)
{
  do something
}

...

更像是这样:

if (condition1 && condition2 && condition3)
{
  do something
}
else if (condition1 && (not condition2) && codition3)
{
  do something
}

...

您也可以简化您的条件。例如,可能有一个condition4等效于condition1 && condition2但不使用&&。考虑condition1 := x <= 100condition2 := x >= 100condition1 && condition2完全等同于x == 100,我肯定会建议更改

...
bool1 = (x >= 100);
...
bool2 = (x <= 100);
...
if (bool1 == true && bool2 == true) { ... }
...

改为:

...
if (x == 100) { ... }
...

我毫不犹豫地将布尔变量明确地用作反模式,但我倾向于尽可能将布尔值保持为R值。

答案 4 :(得分:0)

在这种情况下,我建议单独使用布尔值,如果它们标记良好

但如果它们密切相关(即方向,N / S / E / W),可以做一个巧妙的事情,称为bitmasks 相关的Stack Overflow帖子:what is a bitmask and a mask

如果你有一个街道网格,它们对方向有用,每个街道交叉路口可以有N / S / E / W道路,可以定义为4位数字

让我们定义一些常量

N=1 (0001)
S=2 (0010)
E=4 (0100)
W=8 (1000)

N和E的道路交叉点为N | E

N|E=1|4=5 (0101)

满+交叉(NSEW)将是N | S | E | W

N|S|E|W=1|2|4|8=15 (1111)

如果你要添加一个位掩码,newMask = oldMask | direction

我们将S添加到我们的NE掩码

int newMask = oldMask | S

oldMask为0101,S为0010,newMask为0111

它还有一种简单的方法来检查方向是否存在

如果我们想检查oldMask是否包含N

boolean N? = (oldMask & N) != 0

oldMask&amp; N将隔离N位,使返回值为N或0