Domanda

Ho una domanda per quanto riguarda il modello di visitatore, mi hanno attualmente due assemblee. Il mio primo assieme contiene diverse interfacce.

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

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

public interface IContainer : INode
{
}

E la mia seconda assemblea

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

Quello che voglio fare è evitare la necessità di gettare nella classe ContainerVisitor, voglio fare riferimento direttamente al contenitore. Non posso cambiare l'interfaccia di interfaccia INodeVisitor di utilizzare container. Qualche idea? Devo solo cast?

Saluti

Rohan

È stato utile?

Soluzione

Il cast è inevitabile, ma si potrebbe astratta fuori un po 'per rimuoverlo dalla classe ContainerVisitor reale.

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

Ora ContainerVisitor può derivare da NodeVisitor ed evitare il cast

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

Altri suggerimenti

Non credo sia valida per supporre che si tratta di un'istanza Container. Potrei, perfettamente validamente, scrivere la mia implementazione IContainer, e la vostra applicazione potrebbe soffocare su di esso, rompendo il punto di astrazione un'interfaccia basata su. Si può anche non (validamente) basta cambiare l'API di accettare <=> (utilizzando esplicita implementazione per sostenere <=>), dal momento che potrebbe utilizzare l'interfaccia piuttosto che la classe:

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

Se si vuole il supporto opzionale per qualcosa dalla classe base, allora si sta andando ad avere per usare "come" per rilevarla. Tutto il resto e si stanno rompendo l'astrazione.

A meno che non è possibile definire l'interfaccia IContainer meglio, quindi non sarà in grado di evitare il cast. E come dice Marc, che sconfigge lo scopo di astrazione un'interfaccia basata su.

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

Con l'IContainer meglio definito, i visitatori non avranno bisogno di fare qualsiasi casting.

public class ContainerVisitor : INodeVisitor
{
    public void VisitContainer(IContainer container)
    {
        foreach (IComponent component in container.Components)
        {
            // ...
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top