可以替换链式开关/ goto的设计模式?

UGE*_*EEN 28 c# design-patterns goto

我有一个代码用于将我的应用程序资源更新为当前应用程序版本 应用程序更新后调用此代码.

int version = 1002;   // current app version

switch(version)
{
   case 1001:
      updateTo1002();
      goto case 1002;

   case 1002:
      updateTo1003();
      goto case 1003;

   case 1003:
      updateTo1004();
      goto case 1004;
      break;

   case 1004:
      updateTo1005();
      break;
}
Run Code Online (Sandbox Code Playgroud)

这里我们通过跳转到指定的case块来调用cascade方法.我想知道 - 在这种情况下,使用go(通常被视为这种不良做法!)是一种好习惯吗?我不想一个接一个地调用方法 - 像这样:

updateTo1002()
{
   // do the job
   updateTo1003();
}
updateTo1003()
{
   // do the job
   updateTo1004();
}
Run Code Online (Sandbox Code Playgroud)

有没有设计模式描述这样的问题?

小智 58

好吧,如果我们想要"面向对象",为什么不让对象做对话呢?

var updates = availableUpdates.Where(u => u.version > ver).OrderBy(u => u.version);
foreach (var update in updates) {
  update.apply();
}
Run Code Online (Sandbox Code Playgroud)

  • 最后,一个开始有意义的答案!所有这些`if`,`switch`和`goto`无意义让我害怕! (10认同)
  • Nitpick:这比面向对象更有用.当然,这正是*正确的做法. (5认同)
  • +1.我相信这是我见过的最好的linq案例.优秀. (2认同)

Jar*_*Par 39

在示例中,版本正在增加并始终按顺序调用较早的版本.我认为if这里的一系列陈述可能更合适

if (version == 1001 ) { 
  updateTo1002();
}

if (version <= 1002) {
  updateTo1003();
}

if (version <= 1003) {
  updateTo1004(); 
}

if (version <= 1004) {
  updateTo1005();
}
Run Code Online (Sandbox Code Playgroud)

有些人评论说,随着版本数量的增加,这种方法是不可维护的(想想50左右).在这种情况下,这是一个更容易维护的版本

private List<Tuple<int, Action>> m_upgradeList;

public Program()
{
    m_upgradeList = new List<Tuple<int, Action>> {
        Tuple.Create(1001, new Action(updateTo1002)),
        Tuple.Create(1002, new Action(updateTo1003)),
        Tuple.Create(1003, new Action(updateTo1004)),
        Tuple.Create(1004, new Action(updateTo1005)),
    };
}

public void Upgrade(int version)
{
    foreach (var tuple in m_upgradeList)
    {
        if (version <= tuple.Item1)
        {
            tuple.Item2();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @UGEEN,这个解决方案确实以增量方式调用它们.如果版本以1002开头,它将按顺序调用`updateTo1003`,`updateTo1004`和`updateTo1005`. (5认同)
  • @UGEEN,除非你每次都放入一个大循环或更新版本,否则无法工作 (2认同)

Dav*_*ite 6

我讨厌不提供支持信息的空白语句,但goto相当普遍地被淘汰(有充分理由)并且有更好的方法来实现相同的结果.您可以尝试使用"责任链"模式来实现相同的结果,而不需要goto实现可以变成的"spaghetti-ish"goo.

责任链模式.


And*_*zub 5

goto总是被认为是不好的做法.如果你使用goto,通常很难阅读代码,你总是可以用不同的方式编写代码.

例如,您可以使用链表创建一系列方法和一些处理链的处理器类.(请参阅pst的答案以获得良好的例子.)它更加面向对象和可维护.或者如果你必须再添加一个方法调用beetween 1003和case 1004呢?

当然看到这个问题.

替代文字

  • @Nathan这不是不知情的 - 你不能**看****Velociraptor**?? (20认同)
  • 如果你从不使用goto的理由是Velociraptor攻击,我认为你的论证需要工作. (12认同)
  • 必须同意.这是教条而不是真的.我承认自从27年前我第一次学习Pascal以来我没有使用goto,但它仍然不是一个好的答案. (6认同)
  • 我们如何将此问题扩展到100个版本?这段代码现在看起来如何?我们需要停止查看此示例的非常小的示例数据集,并查看大图并提供设计模式以更完整地解决问题,而不是问题的这个特定实例. (6认同)
  • @Andrew:C#`goto`在其他语言中并不像`goto`那样危险,因为它不允许你从一个块外跳到一个块.虽然`goto`在C#中很少适用,但`goto`并非普遍邪恶; 有一些问题,使用`goto`会产生比使用它更清晰的代码.请注意,我在自己的代码中没有注意到这种情况的任何实例. (3认同)