Frage

i eine Frage in Bezug auf die Besuchermuster, ich habe zur Zeit zwei Baugruppen. Meine erste Baugruppe enthält mehrere Schnittstellen.

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

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

public interface IContainer : INode
{
}

Und meine zweite Baugruppe

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

Was will ich die Notwendigkeit tun zu vermeiden, ist in der ContainerVisitor Klasse zu werfen, möchte ich direkt auf den Container verweisen. Ich kann die Schnittstelle INodeVisitor Schnittstelle ändern Container zu verwenden. Irgendwelche Ideen? Sollte ich nur werfen?

Prost

Rohan

War es hilfreich?

Lösung

Die Besetzung ist unvermeidbar, aber man konnte abstrakt es ein bisschen, um es von der tatsächlichen ContainerVisitor Klasse zu entfernen.

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

Jetzt können ContainerVisitor von NodeVisitor ableiten und vermeiden die Besetzung

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

Andere Tipps

Ich glaube nicht, es ist gültig anzunehmen, dass es sich um eine Container Instanz ist. Ich konnte, vollkommen gültig, schreibe meine eigene IContainer Implementierung und Ihre Umsetzung würde ersticken es, den ganzen Sinn der Schnittstelle basierte Abstraktion zu brechen. Sie können auch nicht (gültig) nur die API ändern Container (mit expliziter Umsetzung unterstützen IContainer) anzunehmen, da ich eher die Schnittstelle verwenden konnte, als die Klasse:

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

Wenn Sie optionalen Support für den etwas von der Basisklasse, dann sind Sie gehen zu müssen, verwenden „wie“ es zu erkennen. Alles andere, und Sie brechen die Abstraktion.

Wenn Sie Ihre IContainer Schnittstelle besser definieren können, dann werden Sie nicht in der Lage sein, die Besetzung zu vermeiden. Und wie Marc sagt, dass Niederlagen den Zweck der Interface-basierte Abstraktion.

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

Mit dem besser definiert IContainer, Ihre Besucher werden kein Casting tun müssen.

public class ContainerVisitor : INodeVisitor
{
    public void VisitContainer(IContainer container)
    {
        foreach (IComponent component in container.Components)
        {
            // ...
        }
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top