开发者

Visitor Pattern Item Tracker

开发者 https://www.devze.com 2023-02-05 10:55 出处:网络
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

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开发者_JS百科? 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; }
}


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

精彩评论

暂无评论...
验证码 换一张
取 消