访客模式,删除需要投射

时间:2009-03-23 03:24:02

标签: c# design-patterns visitor-pattern

我对访问者模式有疑问,我目前有两个程序集。我的第一个程序集包含几个接口。

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

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

public interface IContainer : INode
{
}

我的第二次集会

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

我想要做的是避免在ContainerVisitor类中进行强制转换,我想直接引用Container。我无法更改接口INodeVisitor接口以使用Container。有任何想法吗?我应该演员吗?

干杯

罗汉

3 个答案:

答案 0 :(得分:3)

强制转换是不可避免的,但您可以将其抽象出来以将其从实际的ContainerVisitor类中删除。

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可以从NodeVisitor派生并避免强制转换

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

答案 1 :(得分:1)

我不认为有效认为它是Container实例。完全有效地,我可以编写自己的IContainer实现,并且您的实现会扼杀它,打破了基于接口的抽象的全部要点。你也不能(有效地)只是改变API来接受Container(使用显式实现来支持IContainer),因为我可以使用接口而不是类:

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

如果你想从基类中获得某些东西的可选支持,那么你将不得不使用“as”来检测它。还有别的东西,你正在打破抽象。

答案 2 :(得分:1)

除非您可以更好地定义IContainer界面,否则您将无法避免强制转换。正如Marc所说,这违背了基于接口的抽象的目的。

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

使用更好定义的IContainer,您的访客将无需进行任何投射。

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