Question

J'ai une question concernant le modèle des visiteurs, je actuellement deux assemblées. Mon premier assemblage contient plusieurs interfaces.

public interface INode
{
    void Visit(INodeVisitor visitor);
}

public interface INodeVisitor
{
    void VisitContainer(IContainer container);
}

public interface IContainer : INode
{
}

Et mon deuxième assemblage

    class Program
{
    static void Main(string[] args)
    {
        ContainerVisitor visitor = new ContainerVisitor();
        visitor.VisitContainer(new Container());
    }
}

public class ContainerVisitor : INodeVisitor
{
    public void VisitContainer(IContainer value)
    {
        Container container = value as Container;
        // Do some stuff...
    }
}

public class Container : IContainer
{        
    public void Visit(INodeVisitor visitor)
    {
        visitor.VisitContainer(this);
    }
}

Ce que je veux faire est d'éviter la nécessité de jeter dans la classe ContainerVisitor, je veux faire référence directement le conteneur. Je ne peux pas changer l'interface INodeVisitor d'interface à utiliser le conteneur. Des idées? Devrais-je jeter?

Vive

Rohan

Était-ce utile?

La solution

Le casting est inévitable, mais vous pouvez abstraire un peu pour le retirer de la classe ContainerVisitor réelle.

public class NodeVisitor<T> : INodeVisitor where T : IContainer {
  public void VisitContainer(T node) {
    var container = node as T;
    if ( container != null ) { 
      VisitTyped(container);
    }
  }
  protected abstract VisitContainerTyped(T container);
}

ContainerVisitor peut dériver de NodeVisitor et éviter la distribution

public class ContainerVisitor : NodeVisitor<Container>{
    protected override void VisitContainerTyped(Container container){
        // Do some stuff...
    }
}

Autres conseils

I don't think it is valid to assume that it is a Container instance. I could, perfectly validly, write my own IContainer implementation, and your implementation would choke on it, breaking the whole point of interface-based abstraction. You also can't (validly) just change the API to accept Container (using explicit implementation to support IContainer), since I could be using the interface rather than the class:

INodeVisitor visitor = new ContainerVisitor();
visitor.VisitContainer(myBespokeContainer);

If you want optional support for something from the base-class, then you are going to have to use "as" to detect it. Anything else and you are breaking the abstraction.

Unless you can define your IContainer interface better, then you won't be able to avoid the cast. And as Marc says, that defeats the purpose of the interface-based abstraction.

public interface IContainer : INode
{
    void Add(IComponent component);
    void Add(IComponent component, string name);
    void Remove(IComponent component);
    ComponentCollection Components { get; }
}

With the better defined IContainer, your Visitors won't need to do any casting.

public class ContainerVisitor : INodeVisitor
{
    public void VisitContainer(IContainer container)
    {
        foreach (IComponent component in container.Components)
        {
            // ...
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top