我开始用自上而下的测试来编写代码。我的第一个版本是这样的:
public class Worker
{
public void Execute(Foo foo)
{
//Do X on Foo
//Do Y on Foo
//Do Z on Foo
//Get Bar from Foo
//Do A on Bar
//Do B on Bar
//Do C on Bar
}
}然后这个开始长得更多。所以,我需要添加更多的动作,比如X,Y,Z
我将代码重构为如下内容:
public interface IFooVisitor
{
void Visit(Foo foo);
}
public interface IBarVisitor
{
void Visit(Bar bar);
}
public class Worker
{
public Worker(
IEnumerable<IFooVisitor> fooVisitors,
IEnumerable<IBarVisitor> barVisitors)
{ ... }
public void Execute(Foo foo)
{
foreach(var fooVisitor in fooVisitors) { fooVisitor.Visit(foo); }
var bar = getbarfromfoo(foo);
foreach(var barVisitor in barVisitors) { barVisitor.Visit(bar); }
}
}代码要干净得多,但问题是,在执行访问者时,我需要一些特定的命令。因此,一种选择是向每个访问者添加一个属性,如:
public int Priority {get { return 1; } }这个项目是开源的,完整的代码是这里:
发布于 2011-02-07 19:34:30
你考虑过使用命令链而不是访客吗?
public interface IFooChainLink
{
void Execute(Foo foo);
}
public interface IBarChainLink
{
void Execute(Bar bar);
}
public class Worker
{
public Worker(IFooChainLink fooChain, IBarChainLink barChain)
{ ... }
public void Execute(Foo foo)
{
fooChain.Execute(foo);
var bar = getbarfromfoo(foo);
barChain.Execute(bar);
}
}你的链环应该是这样的
public DoXToFoo : IFooChainLink
{
private static IFooChainLink NextInChain = new DoYToFoo();
public void Execute(Foo foo)
{
// DO STUFF HERE
NextInChain.Execute(foo);
}
}您还需要一个EndOfFooChain
public EndOfFooChain : IFooChainLink
{
public void Execute(Foo foo)
{
// DO NOTHING HERE
}
}您可能需要一个在调用代码中更有意义的起点,例如
public FooChainActivator : IFooChainLink
{
private static IFooChainLink NextInChain = new DoXToFoo();
public void Execute(Foo foo)
{
// DO NOTHING
NextInChain.Execute(foo);
}
}这样,您的链就可以很好地排序,并且可以很容易地将链接插入到链中,甚至连开始和结束都不需要更改调用代码。
如果您希望在一个地方声明您的链序列,您可以将NextInChain作为构造函数参数传递到链的每一层,这样您的调用代码就变成了
var worker = new Worker(
new DoXToFoo(
new DoYToFoo(
new DoZToFoo(
new EndOfFooChain()))),
new DoAToBar(
new DoBToBar(
new DoCToBar(
new EndOfBarChain())))
);这有一个额外的优势,您可以向链中的链接发送参数,但我觉得这比在链接本身中定义NextLinkInChain要麻烦一些。
我想这是个人偏好的问题。
https://codereview.stackexchange.com/questions/677
复制相似问题