访客模式项目跟踪器

发布于 2024-10-12 16:56:28 字数 675 浏览 3 评论 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; }
}

In an implementation of the visitor pattern with interfaces as follow (feel free to tell me if you think the interfaces themselves are wrong), who should be responsible for tracking a list of all the items visited? The visitor or the visitable? Specifically, the tracker must also be responsible for making sure the same item isn't visited twice (if the graph I'm visiting contains circular references).

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黯淡〆 2024-10-19 16:56:28

访问者应该跟踪其访问过的所有项目。与只知道自己可以被访问的 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; items = new List(); 并使用 foreach 语句(使用 IEnumerable 接口)迭代它:

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

The visitor should keep track of all items that it have visited. The visitor is always aware of what it visits, compared to the IVisitable who only knows that it can be visited.

Any other solution would increase the coupling.

As your interfaces, I would change them so that they look like this:

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

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

This means that the visitor should keep a list of visited items if it may not process the same item more than once:

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

Update 2

IEnumerable (iterators) is really an evolution of the visitor pattern. The difference is that you move the loop from inside the visited class to outside.

Update 3

You can create a list: List<MyItem> items = new List<MyItem>(); and iterate it using the foreach statement (which uses the IEnumerable<T> interface):

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

That's the same thing as:

var enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine("The item: " + enumerator.Current);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文