0

在具有以下接口的访问者模式的实现中(如果您认为接口本身错误,请随时告诉我),谁应该负责跟踪所有访问项目的列表?访问者还是可访问者?具体来说,跟踪器还必须负责确保同一项目不会被访问两次(如果我正在访问的图表包含循环引用)。

/// <summary>
/// Defines a type that may accept visitors.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IVisitable<T>
{
    // Methods
    void Accept(T instance, IVisitor<T> visitor);
}

/// <summary>
/// Defines a type that visits objects.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IVisitor<T>
{
    // Methods
    void Visit(IVisitable<T> visitable);

    // Properties
    bool HasCompleted { get; }
}
4

1 回答 1

3

访问者应该跟踪它访问过的所有项目。IVisitable与只知道可以访问的人相比,访问者总是知道它访问了什么。

任何其他解决方案都会增加耦合。

作为您的界面,我会更改它们,使它们看起来像这样:

public interface IVisitable<T>
{
    void Accept(IVisitor<T> visitor);
}

public interface IVisitor<T>
{
    bool Visit(T item);
}

这意味着如果访问者可能不会多次处理同一个项目,则访问者应保留已访问项目的列表:

public class MyVisitor : IVisitor<TheItem>
{
    private List<TheItem> _visitedItems = new List<TheItem>();

    public bool Visit(TheItem item)
    {
         if (_visitedItems.Contains(item)) return true;
         _visitedItems.Add(item);

         //process here. Return false when iteration should be stopped.
    }
}

public class MyItems : IVisitable<TheItem>
{

     public void Accept(IVisitor<TheItem> visitor)
     {
         foreach (var item in items)
         {
             if (!visitor.Visit(item))
                 break;
         }
     }
}

更新 2

IEnumerable(迭代器)实际上是访问者模式的演变。不同之处在于您将循环从访问类内部移动到外部。

更新 3

您可以创建一个列表:List<MyItem> items = new List<MyItem>();并使用foreach语句(使用IEnumerable<T>接口)对其进行迭代:

foreach (var item in items)
{
    //do anything here. use `break` to exit loop.
}

这与以下内容相同:

var enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine("The item: " + enumerator.Current);
}
于 2011-01-18T11:12:35.813 回答