2011-08-24 74 views
21

我只是复习了一些旧代码(有一些空闲时间),并且我注意到了一个相当冗长的开关语句。由于获得新的知识,因为我已经重构它采用以下形式:使用动作词典代替开关语句

private Dictionary<string, Action> createView 
    { 
     get 
     { 
      return new Dictionary<string, Action>() 
      { 
       {"Standard", CreateStudySummaryView}, 
       {"By Group", CreateStudySummaryByGroupView}, 
       {"By Group/Time", CreateViewGroupByHour} 
      }; 
     } 
    } 

你会认为这是很好的做法,或者是这只是被superflous和不必要的情况下?我热衷于确保学到的新技术,仅仅为了它而不聪明,而且他们确实为代码增加了好处。

谢谢。

回答

15

长开关语句是一种经典的难闻气味,并且始终是重构的目标。

这里执行的“标准”步骤是Replace Conditional with Polymorphism。这是Martin Fowler的书Refactoring(1999年出版的11年前)中列出的步骤之一。

既然像对象这样处理函数是很容易的(例如使用Action),这可能就是一个很好的解决方案。

不,我不认为你为了它而聪明。如果我想在未来增加另一个选项,我可以很容易地看到需要做什么。

+0

+1感谢您的链接,我从来没有遇到过重构目录 - 我会给它一个阅读。 –

2

如果代码一旦写入,基本上是静态的,并且不会有太多变化,那么我会坚持使用switch。至少在表面上,你的字典方法很好地适应了更多的动态 - 这是更多的要求。

至于用代码使用这种方法代替开关到处都是,我个人不会在大多数情况下这样做。我的诚恳意见是,为了这个原因,它会很聪明,但它仍然很容易维护。正如我所见,个人对最佳实践的品味是最大的因素。另一方面,正如其他人所说的那样,这可能是长切换语句的可行解决方案。再次,像Strategy Pattern这样的东西也是支持行为变化的好方法。

7

根据您的应用程序,您可以避免始终构造一个新的字典对象,但将其声明为类成员,初始化第一次访问并始终返回相同的实例。但很难说,如果它真的符合你的需求。 就像我的意思

public class MyClass 
{ 
    Dictionary<string, Action> dict = null; 

    private Dictionary<string, Action> createView 
    { 
     get 
     { 
      if(dict == null) 
      { 
       dict = new Dictionary<string, Action>() 
       { 
       {"Standard", CreateStudySummaryView}, 
       {"By Group", CreateStudySummaryByGroupView}, 
       {"By Group/Time", CreateViewGroupByHour} 
       }; 
      } 

      return dict; 
     } 
    } 

} 

编辑

概念的角度来看,我的字典TryGetValue取代长swicth/case是一个不错的解决方案。

希望这有助于...

5

这种方法非常好。我用它不止Action。这对筛选器和选择器也非常有效。就像:

var filters = new Dictionary<string, Func<MyEntity, bool>>() 
{ 
    // ... 
}; 

var query = entities.Where(filters["X"]); 
+0

这也是一个好方法。了解了这门语言的基础知识之后,我现在学习更多复杂的零件更舒适了,而且很有趣,发现这些小技巧:) –