2009-03-23 5 views
3

J'ai une question concernant le modèle de visiteur, j'ai actuellement deux assemblées. Mon premier assemblage contient plusieurs interfaces.Modèle de visiteur, enlever le besoin de lancer

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

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

public interface IContainer : INode 
{ 
} 

Et mon deuxième Assemblée

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 de l'interface INodeVisitor pour utiliser Container. Des idées? Devrais-je jeter?

Vive

Rohan

Répondre

3

Le casting est inévitable, mais vous pouvez abstraire un peu pour l'enlever 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); 
} 

Maintenant ContainerVisitor peut tirer de NodeVisitor et d'éviter la fonte

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

Je ne pense pas que ce soit valide de supposer qu'il est une instance Container. Je pourrais, parfaitement validement, écrire ma propre implémentation IContainer, et votre implémentation l'étoufferait, brisant tout le point de l'abstraction basée sur l'interface. Vous pouvez également ne pas (valablement) il suffit de changer l'API d'accepter Container (en utilisant la mise en œuvre explicite pour soutenir IContainer), puisque je pouvais utiliser l'interface de la classe plutôt que:

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

Si vous souhaitez un support optionnel pour quelque chose de la classe de base, alors vous allez devoir utiliser "as" pour le détecter. Rien d'autre et vous brisez l'abstraction.

1

Si vous ne pouvez pas mieux définir votre interface IContainer, vous ne pourrez pas éviter la distribution. Et comme Marc le dit, cela va à l'encontre du but de l'abstraction basée sur l'interface. Avec le IContainer mieux défini, vos visiteurs n'auront pas besoin d'effectuer de conversion.

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