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