如何在javascript中重构条件逻辑?

时间:2010-09-22 08:51:27

标签: javascript refactoring conditional

我继承了一个用于浏览和配置产品的大型JavaScript(MooTools)应用程序。

其中有一个跟踪产品配置状态的功能。根据产品的状态调用其他功能。

我扩展它以添加一些新功能,但最终在一个大的switch语句中出现了一堆嵌套条件。

我的问题是,你如何重构条件逻辑?是否存在用于跟踪状态的通用(或JS特定)模式/技术?

更新:这是一个伪版本的函数来说明问题:

switchToVariation: function(link) {

  // set the variables      
  // before switch, set state    

  switch ( nextType ) {   
    case 'type1':
      if ( prevType == 'type1' ) {        
        if ( nextIsSameVariation ) {            
          // do stuff                                           
        } else {                                                                              
          if ( nextIsSomethingElse ) {              
            // do stuff
          }          
          // more stuff                      
        }
      } else {        
        // different stuff        
      }
      break;

    case 'type2':        
      if ( prevWasType1 ) {
        // stuff
      } else {
        if (nextIsSameStyle) {
          // stuff
        }
        // more stuff
      }    
      break;    

    default:                       
      // default stuff        
  }          

  // after switch, set state

}

2 个答案:

答案 0 :(得分:3)

当然,主要的答案是:将它分解成更小的部分,每件作品都做得很好。

如果没有看到一个例子,很难更具体,但是你说你在一个大的转换声明中有一个“混乱的条件......”这肯定提供了改进的机会:你可以移动内容每个案例都有自己的功能。

如果你这样做,你有两个选择:要么使函数纯粹地使用你传入它们的参数,这往往会使事情更加模块化,或者使函数闭包操纵外部函数中的数据。我认为后者不太理想 - 用于这些的目的 - 但它可能会更快,因此可以“快速获胜”。

说我们原来有:

function myBigFunction() {
    var v1, v2, v3;

    /* ...set v1, v2, and v3 to various things...*/

    switch (condition) {
        case foo:
            /* ...do lots of stuff involving v1 and v2...*/
            break;

        case bar:
            /* ...do lots of stuff involving v1 only...*/
            break;

        case charlie:
            /* ...do lots of stuff involving v2 and v3...*/
            break;
    }
}

然后:

第一个选项:完全独立的功能

function myBigFunction() {
    var v1, v2, v3;

    /* ...set v1, v2, and v3 to various things...*/

    switch (condition) {
        case foo:
            doFooStuff(v1, v2);
            break;

        case bar:
            doBarStuff(v1);
            break;

        case charlie:
            doCharlieStuff(v2, v3);
            break;
    }
}

function doFooStuff(v1, v2) {
}

function doBarStuff(v1) {
}

function doCharlieStuff(v2, v3) {
}

...当然,你可能需要让这些函数返回一些然后处理它,例如:

    case foo:
        v1 = doFooStuff(v1, v2);
        break;

...如果doFooStuff需要更新v1。如果需要更新v1v2,您可以返回一个数组,或者在传递给v1的对象上设置v2doFooStuff属性等以下是使用属性的示例:将v1v2属性替换为具有vdatav1 属性<的对象(v2) / em>上:

var vdata = {
    v1: "someInitialValue",
    v2: "someInitialValue"
};

...然后拨打doFooStuff

    case foo:
        doFooStuff(vdata);
        break;

...允许doFooStuff同时更新v1v2。但要小心,你不想创建一个包含所有myBigFunction变量的厨房水槽,这会牺牲模块性。

第二个选项:使用闭包并直接使用父函数的数据

function myBigFunction() {
    var v1, v2, v3;

    /* ...set v1, v2, and v3 to various things...*/

    switch (condition) {
        case foo:
            doFooStuff();
            break;

        case bar:
            doBarStuff();
            break;

        case charlie:
            doCharlieStuff();
            break;
    }

    function doFooStuff() {
        // work with v1 and v2 directly
    }

    function doBarStuff() {
        // work with v1 directly
    }

    function doCharlieStuff() {
        // work with v2 and v3 directly
    }
}

请注意,这里,各种子例程是myBigFunction内的闭包,因此它们可以直接访问所有myBigFunction的局部变量。这是更模块化的,但不是第一种选择的完全模块化方法。它也像使用全局变量的函数问题的本地版本:副作用很容易引入并且可能导致麻烦。

第一个选项是首选,但如果它不切实际,第二个选项至少可以帮助您使主线逻辑更清晰。当然,两者的结合可能有效。

答案 1 :(得分:2)

查看State pattern

我写了一篇answer,用Java中的一个例子来解释它,但它可以很容易地用JavaScript实现。它实质上是将系统建模为有限状态机。