【问题标题】:How should I deal with multiple order-dependent conditions?我应该如何处理多个订单相关条件?
【发布时间】:2016-11-03 05:42:30
【问题描述】:

我有多个并发条件,其中的顺序取决于条件。我想出了多种方法来处理这个问题,我需要帮助从我准备的几种方法中选择最好的解决方案。需要考虑的因素有:性能、可重用性、可读性、内存消耗。

方法一:定义多个嵌套的switch case

var collision = {
    detect1: function(subject, target){
        // multiple switch cases
        var shapes = {};
        shapes[subject.type] = subject;
        shapes[target.type] = target;

        switch(subject.type) {
            case 'rectangle':
                switch(target.type) {
                    case 'ellipse':
                        return this.rectWithEllipse(subject, target);
                }
                break;
            case 'ellipse':
                switch(target.type) {
                    case 'rectangle':
                        return this.rectWithEllipse(target, subject);
                }
        }
    },

方法2:在对象注册表中存储类型并根据参数测试切换顺序

    detect2: function(subject, target){
        // object registry and place switch
        var shapes = {};
        shapes[subject.type] = subject;
        shapes[target.type] = target;

        var shape1 = subject;
        var shape2 = target;

        var reverseShapeOrder = function() {
            shape2 = target;
            shape1 = subject;
        };

        if ( shapes.rectangle && shapes.ellipse ) {
            if (subject.type === 'ellipse') {
                reverseShapeOrder();
                return this.rectWithEllipse(shape1, shape2);
            }
        }
    },

方法 3:将类型连接到字符串并根据 indexOf 测试顺序切换顺序。

    detect3: function(subject, target) {
        // string concat and decoding with place switch
        var shapeString = subject.type + target.type;

        var rectIndex =  shapeString.indexOf('rectangle');
        var ellipseIndex = shapeString.indexOf('ellipse');
        var pointIndex = shapeString.indexOf('point');

        var shape1 = subject;
        var shape2 = target;

        var reverseShapeOrder = function() {
            shape2 = target;
            shape1 = subject;
        };

        if (rectIndex && ellipseIndex) {
            if (ellipseIndex < rectIndex) {
                reverseShapeOrder();
            }
            return this.rectWithEllipse(shape1, shape2);
        }
    },

方法 4:标准的传统 if-else 语句

    // traditional logic
    detect4: function(subject, target) {
        if (subject.type === 'rectangle'  && target.type === 'ellipse') {
            return this.rectWithEllipse(subject, target);
        }
        else if (subject.type ==='ellipse' && target.type === 'rectangle') {
            return this.rectWithEllipse(target, subject);
        }
    },
    rectWithEllipse: function(rect, ellipse) {
        return false;
    }
};   

方法 5:具有参考功能的动态选择器(感谢@Bergi 的即时选择器建议)

detect5: function(subject, target) {
        return this[subject.type + '_with_' + target.type](subject, target);
    },
    rect_with_ellipse: function(rect, ellipse) {
        return false;
    },
    ellipse_with_rect: function(rect, ellipse) {
        this.rect_with_ellipse(ellipse, rect);
    }
};   

请帮助我选择最佳解决方案并了解为什么它是最好的。谢谢

请记住,完整的组合列表会更大,如下所示:

rectWithPoint: function(rect, point) {
    return false;
},
rectWithEllipse: function(rect, ellipse) {
    return false;
},
rectWithRect: function(rect, rect) {
    return false;
},
ellipseWithPoint: function(ellipse, point) {
    return false;
},
ellipseWithEllipse: function(ellipse, ellipse) {
    return false;
}

【问题讨论】:

  • 方法五:只需致电this[subject.type + "With" + target.type](target, subject)(可能有些名字)
  • 附带问题:此代码是按原样使用,还是通过 Google Closure Compiler 或类似工具传递?
  • 代码将按原样使用。但最终我想理所当然地编译我的所有代码。 @阿诺德
  • @Bergi 看看我添加了什么
  • 确实有很多方法可以做到这一点,我不确定哪一种是最好的。您可以执行switch(type0 &lt; type1 ? type0 | (type1 &lt;&lt; 4) : type1 | (type0 &lt;&lt; 4)) 以确保具有最低 ID 的类型进入最低有效位。或者您可以为这两种组合放置两个连续的“案例”,然后是它们的公共代码块。

标签: javascript performance readability


【解决方案1】:

我将定义一个映射如下,这将使其易于扩展:

targets: {
  rectangle: {
    point: function rectWithPoint(rect, point) {
      return false;
    },
    ellipse: function rectWithEllipse(rect, ellipse) {
      return false;
    },
    rectangle: function rectWithRect(rectLhs, rectRhs) {
      return false;
    }
  },
  ellipse: {
    point: function ellipseWithPoint(ellipse, point) {
      return false;
    },
    ellipse: function ellipseWithEllipse(ellipseLhs, ellipseRhs) {
      return false;
    }
  }
},

detect5: function (subject, target) {
  var tmp, candidates = this.targets[subject];

  if (!candidates) {
    tmp = subject;
    subject = target;
    target = tmp;
    candidates = this.targets[subject];
  }

  if (candidates && candidates.hasOwnProperty(target)) {
    return candidates[target].call(this, subject, target);
  }

  return false;
}

【讨论】:

  • 这是一个我没有想到的有趣方法。我要花点时间考虑一下。与其他方法相比,这种方法有哪些优缺点?
  • 添加一个新的碰撞检测器,只需要定义一对键:(subject -> target) -> predicate。当您支持更多形状时,这将使您的代码保持干燥、简单和简洁。这是一种常用的图建模方法,其中一种是简单的。
  • 另外,我想说这是最易读的方法
  • 我仍然很想听听其他人怎么说。但这是非常合理的推理。非常感谢:) @Dylon
  • @Dylon 顺便说一句,Rhs 和 Lhs 代表什么?
猜你喜欢
  • 2015-11-05
  • 2021-03-25
  • 2021-03-03
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多