3

我有一个关于访客模式的问题,我目前有两个程序集。我的第一个程序集包含几个接口。

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。有任何想法吗?我应该投吗?

干杯

罗汉

4

3 回答 3

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...
    }
}
于 2009-03-23T03:47:58.563 回答
1

我认为假设它是一个实例是不正确的。Container我可以完全有效地编写自己的IContainer实现,而您的实现会扼杀它,从而打破基于接口的抽象的全部要点。您也不能(有效地)将 API 更改为接受Container(使用显式实现来支持IContainer),因为我可能使用的是接口而不是类:

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

如果您想对基类中的某些内容提供可选支持,那么您将不得不使用“as”来检测它。其他任何事情,你都在打破抽象。

于 2009-03-23T05:27:45.157 回答
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)
        {
            // ...
        }
    }
}
于 2009-03-23T07:05:53.253 回答