访客模式项跟踪器

时间:2011-01-18 11:08:59

标签: c# .net visitor

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

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

1 个答案:

答案 0 :(得分: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);
}