我一直在查看一些代码,看到我的同事正在使用“标记类”来控制程序逻辑(参见下面的设计示例)。它似乎工作得很好,代码读起来非常好,但有一些东西闻起来......
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 {}
}
实现同样效果的更好方法是什么?枚举?属性?
答案 0 :(得分:8)
标记 接口 是一种更好的做法,因为它们提供了更大的灵活性。
然而,在这种特定情况下,我认为虚拟调度是一种更好的解决方案。
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() { }
}
}
答案 1 :(得分:4)
您要做的是用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方法的代码。
答案 2 :(得分:2)
我看到这个问题已经过时了,但我觉得所有答案都错过了这一点。
如果示例完全说明了所需功能的范围,那么此处使用的相应构造将是枚举类型。枚举类型是值类型;它们的功能与命名数值常量基本相同,具有出色的IDE自动完成支持。以下是修改为使用枚举类型的示例:
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是对这段代码最简单的改进。
答案 3 :(得分:1)
他几乎在那里,但并不完全,这可能就是你所看到的。关于该类型的if语句是难闻的气味。应该在ProcessingMethod基类上执行某些操作,并且扩展它的每个类型都应该有自己的版本。
public void DoSomething(ProcessingMethod method) {
method.DoSomething();
}
答案 4 :(得分:0)
如何将处理逻辑委托给特定的子类? 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
}
}
答案 5 :(得分:0)
是的,这闻起来很糟糕。如果你想做一些平行的事情:
public class Parallel : ProcessingMethod{}
那么你将不得不改变很多代码。
答案 6 :(得分:0)
框架设计指南一书建议不要使用标记接口(可能是标记类),而是选择属性intead。话虽如此,本书继续说明使用is
(正如你所做的)比使用反射检查属性要快得多。