3 Stimmen

Visitor Pattern, entfernen Sie die Notwendigkeit zu werfen

Ich habe eine Frage bezüglich des Besuchermusters. Ich habe derzeit 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 ich tun möchte, ist die Notwendigkeit zu vermeiden, in der ContainerVisitor-Klasse zu casten, ich möchte den Container direkt verweisen. Ich kann die Schnittstelle INodeVisitor nicht ändern, um Container zu verwenden. Hat jemand eine Idee? Sollte ich einfach casten?

Prost

Rohan

3voto

JaredPar Punkte 699699

Der Cast ist unvermeidlich, aber man könnte ihn ein wenig abstrahieren, um ihn aus der eigentlichen 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 kann ContainerVisitor von NodeVisitor abgeleitet werden und den Cast vermeiden

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

1voto

Marc Gravell Punkte 970173

Ich glaube nicht, dass es das ist. gültig anzunehmen, dass es sich um eine Container Instanz. Ich könnte mit Fug und Recht meine eigene IContainer Implementierung, und Ihre Implementierung würde daran ersticken, was den ganzen Sinn der schnittstellenbasierten Abstraktion zunichte macht. Sie können auch nicht (gültig) einfach die API ändern, um zu akzeptieren Container (mit expliziter Implementierung zur Unterstützung IContainer ), da ich die Schnittstelle und nicht die Klasse verwenden könnte:

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

Wenn Sie optionale Unterstützung für etwas aus der Basisklasse wünschen, dann müssen Sie "as" verwenden, um es zu erkennen. Alles andere ist ein Bruch der Abstraktion.

1voto

Mufaka Punkte 2326

Es sei denn, Sie können Ihre IContainer-Schnittstelle besser definieren, dann werden Sie den Cast nicht vermeiden können. Und wie Marc schon sagt, macht das den Zweck der schnittstellenbasierten Abstraktion zunichte.

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

Mit dem besser definierten IContainer müssen Ihre Besucher kein Casting mehr durchführen.

public class ContainerVisitor : INodeVisitor
{
    public void VisitContainer(IContainer container)
    {
        foreach (IComponent component in container.Components)
        {
            // ...
        }
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X