【问题标题】:Using marker classes to control logic flow使用标记类来控制逻辑流
【发布时间】:2011-10-03 10:50:58
【问题描述】:

我一直在查看一些代码,发现我的一位同事正在使用“标记类”来控制程序逻辑(请参见下面的人为示例)。它似乎工作得很好,代码读起来也很好,但是它有一些味道......

namespace ConsoleApplication4983
{
    public class MyClass
    {
        static void Main()
        {
            var c = new MyClass();
            c.DoSomething(new Sequential());
            c.DoSomething(new Random());
        }

        public void DoSomething(ProcessingMethod method)
        {
            if (method is Sequential)
            {
                // do something sequential
            }
            else if (method is Random)
            {
                // do something random
            }
        }
    }

    public class ProcessingMethod {}
    public class Sequential : ProcessingMethod {}
    public class Random : ProcessingMethod {}
}

实现相同效果的更好方法是什么?枚举?属性?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    标记界面是一种更好的做法,因为它们提供了更大的灵活性。

    但是在这种特定情况下,我认为虚拟调度是一个更好的解决方案。

    using System;
    
    namespace ConsoleApplication4983
    {
        public class MyClass
        {
            static void Main()
            {
                var c = new MyClass();
                c.DoSomething(new Sequential());
                c.DoSomething(new Random());
            }
    
            public void DoSomething(ProcessingMethod method)
            {
                method.Foo();
            }
        }
    
        public class ProcessingMethod
        {
            public virtual void Foo() { }
        }
        public class Sequential : ProcessingMethod
        {
            public override void Foo() { }
        }
        public class Random : ProcessingMethod
        {
            public override void Foo() { }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您想要做的是用strategy pattern 替换它。策略定义了某事是如何完成的——即算法。

      public interface IProcessingMethod
      {
          void Process();
      }
      
      public class SequentialProcess : IProcessingMethod
      {
          public void Process( IProcessable obj )
          {
               do something sequentially with the obj
          }
      }
      
      public class ParallelProcess : IProcessingMethod
      {
          public void Process( IProcessable obj )
          {
              do something in parallel with the obj
          }
      }
      
      public interface IProcessable
      {
          void Process( IProcessingMethod method );
      }
      
      public class MyClass : IProcessable
      {
           public void Process( IProcessingMethod method )
           {
               method.Process( this );
           }
      }
      
      ...
      
      var obj = new MyClass();
      obj.Process( new SequentialProcess() );
      

      现在,如果我有一个新的 ProcessingMethod 类型,我只需要为该方法创建一个类,并更改确定将哪种处理方法注入到我的 IProcessable 对象的 Process 方法的代码。

      【讨论】:

        【解决方案3】:

        他几乎就在那里,但并不完全,这可能就是你所看到的。类型上的 if 语句是难闻的气味。应该在 ProcessingMethod 基类上做一些事情,并且扩展它的每个类型都应该有自己的版本。

        public void DoSomething(ProcessingMethod method)    {
           method.DoSomething();
        }
        

        【讨论】:

          【解决方案4】:

          我看到这个问题很老,但我觉得所有的答案都没有抓住重点。

          如果该示例充分说明了所需功能的范围,那么此处使用的适当构造将是 Enum 类型。枚举类型是值类型;它们的功能本质上类似于命名的数字常量,具有出色的 IDE 自动完成支持。下面是修改为使用 Enum 类型的示例:

          namespace ConsoleApplication4983
          {
              public class MyClass
              {
                  static void Main()
                  {
                      var c = new MyClass();
                      c.DoSomething(ProcessingMethod.Sequential);
                      c.DoSomething(ProcessingMethod.Random);
                  }
          
                  public void DoSomething(ProcessingMethod method)
                  {
                      if (method == ProcessingMethod.Sequential)
                      {
                          // do something sequential
                      }
                      else if (method == ProcessingMethod.Random)
                      {
                          // do something random
                      }
                  }
              }
          
              public enum ProcessingMethod
              {
                  Sequential,
                  Random
              }
          }
          

          其他答案是参考更复杂的模式。我认为他们对“标记类”一词读得太多了。有时策略模式、虚拟调度等是一个不错的方法,但在这种情况下,我认为 Enum 是对这段代码进行的最简单的改进。

          【讨论】:

            【解决方案5】:

            如何将处理逻辑委托给特定的子类? ProcessingMethod 会有一些由每个子类实现的抽象方法。

            public void DoSomething(ProcessingMethod method)
            {
              method.Process();
            }
            
            public abstract class ProcessingMethod
            {
              public abstract void Process();
            }
            
            public class Sequental : ProcessingMethod
            {
              public override void Process()
              {
                // do something sequential
              }
            }
            
            public class Random : ProcessingMethod
            {
              public override void Process()
              {
                // do something random
              }
            }
            

            【讨论】:

              【解决方案6】:

              是的,这闻起来很糟糕。如果你想做一些并行的事情:

              public class Parallel : ProcessingMethod{}
              

              那么您将不得不更改大量代码。

              【讨论】:

                【解决方案7】:

                Framework Design Guidelines 一书建议不要使用标记接口(并且可能是标记类),而是优先使用属性。话虽如此,这本书确实继续说使用is(正如你所做的那样)比使用反射检查属性要快得多。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-06-11
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-08-05
                  相关资源
                  最近更新 更多