简化巨大的if语句 - 设计模式?

时间:2011-02-10 19:46:08

标签: php

我可能有一组看起来像这样的if语句:

if (a and b and c and d) {
  // do stuff
} else (!a and b and c and d) {
  // do something else
} else (!a and !b and c and D) {
  // do yet something else
} ...

等所有可能的排列。

我想到了这样做:

switch ((a ? 'Y' : 'N') . (b ? 'Y' : 'N') . (c ? 'Y' : 'N') . (d ? 'Y' : 'N')) {

  case 'YNYN':
    // do stuff
    break;

  case 'NNNN':
    // etc.
    break;

}

有更好的方法吗?

5 个答案:

答案 0 :(得分:8)

我可能会做的事情(不知道具体细节)是为每个州建立一系列的课程。然后将 doStuff 推送到该类:

class DoStuff { //The Client
    protected $strategies = array();
    public function addStrategy(iDoStuffStrategy $strategy) {
        $this->strategies[] = $strategy;
    }
    public function doStuff ($a, $b, $c, $d) {
        foreach ($this->strategies as $strategy) {
            if ($strategy->test($a, $b, $c, $d)) {
                return $strategy->doStuff();
            }
        }
        throw new RuntimeException('Unhandleable Situation!');
    }
}

interface iDoStuffStrategy {
    // Return a bool if you can handle this situation
    public function test($a, $b, $c, $d);
    // Execute the implementation
    public function doStuff();
}

然后,每个班级看起来像这样:

public function StrategyFoo implements iDoStuffStrategy {
    public function test($a, $b, $c, $d) {
        return $a && $b && $c && $d;
    }
    public function doStuff() {
        //DoStuff!
    }
}
public function StrategyBar implements iDoStuffStrategy {
    public function test($a, $b, $c, $d) {
        return !$a && $b && $c && $d;
    }
    public function doStuff() {
        //DoStuff!
    }
}

它基本上是Strategy Pattern的实现。这样做可以让你分离出决策树。

答案 1 :(得分:0)

我认为您应该考虑使用决策树解决此问题,其中不同的节点可能是最终状态。 然后你可以在树上组合你的问题,并摆脱所有这些ifs ....

答案 2 :(得分:0)

当我需要根据一组条件汇总数据时,我对您的案例陈述采取了类似的方法,其中有五个开关可以打开或关闭。

为了处理有关可能情况的聚合信息,这工作正常,但在该用例之外,如果确实存在n ^ 2个不同的操作,那么我将坚持使用多个if语句。如果没有那么多排列,我会将相似的结果组合在一起以减少ifs的数量。

答案 3 :(得分:0)

是的,还有更好的方法。

哦,你想要更多细节吗?好吧,你似乎有一些带有四个变量的真值表。是否有16种可能的结果(2 ^ 4),或者您只对一个子集感兴趣?如果有一个变量具有大致相同数量的结果,可以使用它作为最顶层的if语句,并使用嵌套的ifs。

if (b) {
  // cases where b is true
  if (...)
    ...
} else {
  // cases where b is false
  if (...)
    ...
}

您也可以使用switch语句,而不是由Y和N组成的字符串使用位域。

答案 4 :(得分:0)

我会将你的四个布尔值视为四位,因此是0到15之间的整数。我将创建一个包含16个元素的数组,并在数组的每个元素中存储一个函数指针。每次你需要这样做时,我都会将布尔值计算成一个位模式,转换为int,然后调用存储在数组索引中的方法。

我知道你在问PHP,我恐怕不知道。在C#中,你可以这样做:

static class Multiplexer
{
    public static string Multiplex(bool a, bool b, bool c, bool d)
    {
        var i = 0;
        i |= (a ? 1 : 0) << 3;
        i |= (b ? 1 : 0) << 2;
        i |= (c ? 1 : 0) << 1;
        i |= (d ? 1 : 0);
        return _functions[i]();
    }

    private static Func<string>[] _functions = new Func<string>[] {
        () => { return "pie";},
        () => { return "index 1"; },
        () => { return DateTime.Now.ToString(); },
        () => { return "pie";},
        () => { return "index 1"; },
        () => { return DateTime.Now.ToString(); },
        () => { return Assembly.GetExecutingAssembly().FullName; },
        () => { return ""; },
        () => { return "pie";},
        () => { return "index 1"; },
        () => { return DateTime.Now.ToString(); },
        () => { return "pie";},
        () => { return "index 1"; },
        () => { return DateTime.Now.ToString(); },
        () => { return Assembly.GetExecutingAssembly().FullName; },
        () => { return ""; }};
}