【问题标题】:Deal with a lot of if-else , switch处理很多 if-else , switch
【发布时间】:2010-09-01 11:57:41
【问题描述】:

处理此类问题的最佳方法是什么:

if(key==Space)
{
    switch(weapon)
    {
        case GUN:
            p->shotGun();
            break; 
        case BOW:
            p->shotBow();
            break;
    }
}
else if(key==Enter)
{
    //...
}
else if(key==Up)
{
    //...
}

【问题讨论】:

  • 对我来说似乎没问题...key 是什么类型?

标签: c++ if-statement switch-statement


【解决方案1】:

一维一分为二:

switch (key)
{
  case Space:
    ProcessSpaceCmd ();
    break;

  case Enter:
    ProcessEnterCmd ();
    break;

  case Up:
    ProcessUpCmd ();
    break;
}

看看哪个尺寸更长,[key][weapon] 并取最短的作为外部开关。

【讨论】:

  • 如果开发人员不小心,这可能会导致意大利面仓库,但考虑到 OP 的需求,这是明智的。
【解决方案2】:

您可能需要考虑使用Command 和/或Strategy 模式。 Command 模式似乎很适合外部 if/else,而 Strategy 模式似乎很适合内部 switch。

  cmd = Command->GetCommand( key );
  cmd->Perform();

并在执行与空格键关联的命令

  weapon = PlayState->GetCurrentWeapon();
  weapon->Fire();

请注意,后者依赖于一些全局缓存/状态来保存当前武器(策略)。

这样做的效果是将 if/else 逻辑移动到您确定当前命令的工厂方法中。选择哪个命令会选择 if/else 分支之一。将当前武器存储在播放状态可以让您轻松选择调用哪个武器的 Fire 方法,因此选择哪个武器的开关“逻辑”移动到该状态的武器选择逻辑并完全“消失”。每个武器策略都知道如何执行它自己的“开火”逻辑。

【讨论】:

  • 它可以很容易地适应而不需要任何全局。
【解决方案3】:

我倾向于使用地图类型表达式:

unordered_map<KEY_PRESS,ICommand> myCommands;
unordered_map<KEY_PRESS,ICommand>::const_iterator currentCommand = myCommands.find( key );
if( currendCommand != myCommands.end() ){
    currentCommand->performAction( weapon );
}

再说一次,如果您将武器制作成物体而不是旗帜,您可以避免使用重载函数模式。

【讨论】:

    【解决方案4】:

    由于它是 C++,您可能希望利用它的面向对象方面。为 IProjectileWeapon 等武器创建一个接口,并创建一个实现该接口的弓和枪类。然后,当您调用 Shoot() 方法时,它将使用正确的行为。这将摆脱武器的 switch 语句。让 Character 类将武器作为成员并使用 UseWeapon() 作为方法可能会更好。所以 UseWeapon() 方法会调用武器的 Shoot() 方法。

    对于移动,在 Character 类中添加一个移动命令并传递角色应该移动的方向。

    【讨论】:

      【解决方案5】:

      或者,如果您真的想摆脱 if-else,您可以在关键代码和方法之间使用某种形式的映射。取决于键码是否连续,它可以是映射或简单地由键码索引的数组,例如:

      KeyMethods[key]();

      【讨论】:

        【解决方案6】:

        另一种可能性:

        class Weapon {
            public:
            abstract void shoot();
        }
        
        class Gun: public Weapon {
            public:
            void shoot();
        }
        
        class Bow: public Weapon {
            public:
            void shoot();
        }
        
        if(key==Space)
        {
            weapon.shoot();
        }
        else if(key==Enter)
        {
            //...
        }
        else if(key==Up)
        {
            //...
        }
        

        至于if 声明的长列,没关系。如果您使用整数,switch 语句也可以工作。但是在每个语句中都有break 语句可能会分散注意力,忘记它可能是灾难性的。如果您需要内部循环中的性能关键代码的速度,这一点更为重要。 (else if 依次评估每个选项,直到找到匹配项。switch 直接跳转到正确的选项。)

        【讨论】:

        • 您确定“抽象”关键字吗?也许它应该是“虚拟的”?但是你的观点很好。使用多态绝对是比使用“switch”更好的方法...
        【解决方案7】:

        嵌套 switch 语句的级别如何?为了更好的可读性,我还将第二级开关重构为单独的功能。

        【讨论】:

          【解决方案8】:

          我建议至少将每个 If 的内容分成它自己的函数。

          if(key == Space)
              FureCurrentWeapon();
          else if(key == Enter)
              Activate();
          else if(key == Up)
              WalkForwards();
          

          我之前使用的另一种方法是创建一个基类,每个接收键盘输入的类都可以从该基类派生。保留一个派生自它的类的列表,然后在每次收到输入时遍历该列表,传递按下的键并让他们根据需要处理它。

          【讨论】:

            【解决方案9】:

            使您的武器类虚拟化。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2023-04-09
              • 1970-01-01
              • 2019-12-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多