我有很多IF句子,每个句子都有一个功能 是否有一种明显的方法可以更简单地编写此代码? 每个IF都会启动不同的功能,但它看起来仍然有点矫枉过正。
if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool == '') {
$this->AllTime();
}
if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool == '') {
$this->ByMachine();
}
if ($this->machine == '' AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool == '') {
$this->ByDate();
}
if ($this->machine <> 0 AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool == '') {
$this->ByMachineByDate();
}
if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool == '') {
$this->ByDateLike();
}
if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool == '') {
$this->ByMachineByDateLike();
}
if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool <> 0) {
$this->ByArticle();
}
if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like == '' AND $this->article_or_tool <> 0) {
$this->ByMachineByArticle();
}
if ($this->machine == '' AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool <> 0) {
$this->ByDateByArticle();
}
if ($this->machine == '' AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool <> 0) {
$this->ByDateLikeByArticle();
}
if ($this->machine <> 0 AND $this->date_from <> 0 AND $this->date_to <> 0 AND $this->date_like == '' AND $this->article_or_tool <> 0) {
$this->ByMachineByDateByArticle();
}
if ($this->machine <> 0 AND $this->date_from == '' AND $this->date_to == '' AND $this->date_like <> 0 AND $this->article_or_tool <> 0) {
$this->ByMachineByDateLikeByArticle();
}
解
以下是重构后的代码:
function MethodPicker() {
$machine = $this->machine <> 0;
$date_from = $this->date_from <> 0;
$date_to = $this->date_to <> 0;
$date_like = $this->date_like <> 0;
$article_or_tool = $this->article_or_tool <> 0;
$decision = array($machine, $date_from, $date_to, $date_like, $article_or_tool);
$decisions = array(
'AllTime' => array(false, false, false, false, false ),
'ByMachine' => array(true, false, false, false, false ),
'ByDate' => array(false, true, true, false, false ),
'ByMachineByDate' => array(true, true, true, false, false ),
'ByDateLike' => array(false, false, false, true, false ),
'ByMachineByDateLike' => array(true, false, false, true, false ),
'ByArticle' => array(false, false, false, false, true ),
'ByMachineByArticle' => array(true, false, false, false, true ),
'ByDateByArticle' => array(false, true, true, false, true ),
'ByDateLikeByArticle' => array(false, false, false, true, true ),
'ByMachineByDateByArticle' => array(true, true, true, false, true ),
'ByMachineByDateLikeByArticle' => array(true, false, false, true, true ),
);
$method = array_keys($decisions, $decision, true);
$method && list($method) = $method;
$method && $this->$method();
}
答案 0 :(得分:2)
也许你真的需要所有这些决定,但你可以让它更容易阅读。您可以先将此值设置为有意义的变量,而不是在if语句中多次写入$this->machine == ''
。
$machineIsEmpty = $this->machine == '' || $this->machine == 0;
$dateFromIsEmpty = $this->date_from == '' || $this->machine == 0;
...
if ($machineIsEmpty && $dateFromIsEmpty && $dateToIsEmpty && $dateLikeIsEmpty && $articleOrToolIsEmpty)
{
$this->AllTime();
}
else if (!$machineIsEmpty && $dateFromIsEmpty && $dateToIsEmpty && $dateLikeIsEmpty && $articleOrToolIsEmpty)
{
$this->ByMachine();
}
...
在这个例子中,我假设有两件事:首先我怀疑你想要将值''
和0
都处理为未设置。我不确定这一点,因为没有任何情况下您使用值0
做了任何事情。
其次我假设如果调用了一个函数,你不想再调用其他函数,所以我在下一个if之前添加了一个else。
在我看来,嵌套if语句会使代码更难以阅读 ,因为你必须记住你当前在if语句的哪个级别。
另一种方法是使用决策矩阵。您可以编写一个包含所有可能组合的数组,每个组合都知道函数名称。
$myObject = new TestClass();
$myObject->DoAction($machineIsSet, $dateFromIsSet, $dateToIsSet, $dateLikeIsSet, $articleToolIsSet);
class TestClass
{
private $actionMatrix = array(
// machine, dateFrom, dateTo, dateLike, articleOrTool, action
array(false, false, false, false, false, 'AllTime'),
array(true, false, false, false, false, 'ByMachine')
);
public function DoAction($machine, $dateFrom, $dateTo, $dateLike, $articleOrTool)
{
foreach($this->actionMatrix as $action)
{
if (($action[0] == $machine) && ($action[1] == $dateFrom) && ($action[2] == $dateTo) && ($action[3] == $dateLike) && ($action[4] == $articleOrToolLike))
{
$functionName = $action[5];
$this->$functionName(); // call the function
break;
}
}
// no action found, maybe we want some error handling here?
}
public function AllTime()
{
echo('AllTime');
}
public function ByMachine()
{
echo('ByMachine');
}
}
答案 1 :(得分:2)
首先,我会做一些标准的重构。不知道为什么我这样做,但这是什么:
使用局部变量替换属性,例如
$machine = $this->machine;
同样适用于条件但是更接近条件时,很明显只有每个变量有两个状态,所以这实际上只是每个变量的一个条件(参见Type Juggling)在true
或false
中。相反,分配条件:
$machine = $this->machine == '' || $this->machine == 0;
(积分转到martinstoeckli了解正确条件)
这将是一个开始。 if条款到现在为止已经改变了,并且会更加紧凑。但是,为何停在这里?目前有一个决定:
$decision = [$machine, $date_from, $date_to, $date_like, $article_or_tool];
有一系列决定可供选择:
$decisions = [
'AllTime' => [true, true, true, true, true],
...
];
所以需要做的就是找到决定并执行方法:
$method = array_keys($decisions, $decision, true);
$method && $this->$method();
if块已变为矩阵。该函数已映射到它的一个状态。
你松开了字段上的名字,但是,你可以通过评论来解决这个问题:
$decisions = [
// machine from to like article
'AllTime' => [true , true, true, true, true],
...
];
一目了然:
$machine = $this->machine == '' || $this->machine == 0;
... # 4 more times
$decision = [$machine, $date_from, $date_to, $date_like, $article_or_tool];
$decisions = [
'AllTime' => [true, true, true, true, true],
... # 11 more times
];
$method = array_keys($decisions, $decision, true);
$method && $this->$method();
如果这个类代表一个值对象,我建议你将决策移动到它自己的类型中,然后将该决策类型用作单个方法对象。将使您以后能够更轻松地做出不同的决策。
答案 2 :(得分:1)
很多都是重复,所以你可以嵌套条件来删除冗余,例如:
if ($this->machine == '') {
// do everything requiring empty 'machine' string
// remove condition from all subsequent ifs in this context
} else if ($this-> machine <> 0) {
}
我没有时间或倾向于完成所有代码并实际为您执行此操作,但这是一个想法,应该为您提供足够的信息来实现作为读者的练习。 (:
答案 3 :(得分:0)
有时候,如果您的条件不同,则不可能,但在这种情况下,您可以从分组if()
开始,因为许多人都有相同的条件。例如,而不是吨吨
if( $this->machine <> 0 AND .... )
你可以将它们组合在一起:
if( $this->machine <> 0 ) {
// all related ifs there
}
然后继续下一个“级别”的条件。虽然这可能不会减少if()
的总数,但您的代码将比现在更具可读性。
答案 4 :(得分:0)
正如我所见,你有一个约定你的方法的约定。 如果我有这样的代码和这样的约定,我会使用调用方法按名称重构它,这样你的代码将非常简短,易于阅读和维护
$method = '';
if (this->machine <> 0) $method.="ByMachine";
if ($this->date_from <> 0 AND $this->date_to <> 0) $method.="ByDate"
.....
//here you have full $method name ByMachineByDateByArticle or ByMachineByDateByArticle etc
if($method){
call_user_func_array(array($this, $method));
}