Посетители Сортировки


Я начал писать код с сверху вниз тесты. Моя первая версия, вырастет во что-то вроде этого:

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

Я refactorized код в что-то вроде:

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; } }

Проект OpenSource и полный код здесь:

  • IAbcVisitor является ICloneVisitor
  • IXyzVisitor является IPostWeaveAction


Комментарии
1 ответ

Вы рассматривали с помощью субординации, а не посетителя?

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 в одной сами.

Я думаю, что это вопрос личных предпочтений.

5
ответ дан 7 февраля 2011 в 07:02 Источник Поделиться