访问者模式的变体 - 默认的无操作访问方法,所以当我添加元素类型时,我不需要更改所有访问者?

时间:2010-11-01 10:44:16

标签: c# oop .net-4.0

我有一组要执行操作的元素。经典的“访客”模式不适用于我的情况,因为: -

  • 我的元素类型不稳定。
  • 我想基于接口实现访问,并且我的一些元素实现了需要不同访问者访问的多个接口 - 这导致这些类型的Accept方法中的模糊调用。

我的大多数访问者并不关心我的大多数元素。即使我可以使用经典的访客模式,绝大多数的访问方法都是无操作。

我想要一个访客模式的变体,如下所示: -

class Visitor
{
  // called when I'm Accepted by a ThingICareAbout
  void Visit(ElementICareAbout e)
  {
    // Do whatever needs done.
  }
  // called when I'm Accepted by anything else
  void Visit(Element e)
  {
    // Do nothing.
  }
}

我想出了以下内容: -

相关问题:c# generic method overload not consistent with abstract Visitor pattern

public interface IAcceptsVisitor
{
  void Accept<T>( IVisitor<T> v );
}

public interface IVisitor<T>
{
  void Visit( T e );
  void Visit<X>( X e );
}

public class Element : IAcceptsVisitor
{
  public bool Visited { get; set; }

  public Element ()
  {
    Visited = false;
  }
  public void Accept<U>( IVisitor<U> v )
  {
    v.Visit( this );
  }
}

public class Visitor : IVisitor<Element>
{
  public void Visit( Element e )
  {
    e.Visited = true;
  }
  public void Visit<X>( X e )
  {
    // Do nothing
  }
}

但是这不起作用,因为如果编译器在编译时静态地知道它将起作用,编译器只能更喜欢非泛型的Visit方法。

  1. 有没有办法完成上述工作?
  2. 还有另一种方法吗?
  3. 关于2)我已经看到Dynamic Dispatching被吹捧为访问者模式的“高级”替代方案,但这真的“更好”而不仅仅是: -

    foreach (ThingICareAbout in things.OfType<ThingICareAbout>())
    

    另外值得注意的是:我正在使用.NET 4,所以如果动态类型有帮助,我愿意试一试。

    编辑:我根据动态关键字提供了自己的答案。但是,我仍然对听到其他方法非常感兴趣。

1 个答案:

答案 0 :(得分:0)

关于Dynamic关键字,这是我到目前为止: -

public class ThingIDontCareAbout: IAcceptsVisitor
{
}

public class ThingICareAbout: IAcceptsVisitor
{
  public bool Visited { get; set; }

  public AdvancedElement()
  {
    Visited = false;
  }
}

public class Visitor
{
  public void Visit( IAcceptsVisitor e )
  {
    dynamic d = e;
    this.DynamicVisit( d );
  }

  private void DynamicVisit( IAcceptsVisitor e )
  {
    // Do nothing.
  }

  private void DynamicVisit( ThingICareAbout e )
  {
    e.Visited = true;
  }
}

你打电话给: -

Visitor v = new Visitor();
foreach (IAcceptsVisitor e in things) { v.Visit(e); }

去配置此vs类型检查。我特别感兴趣听到你的意见,将其与: -

进行比较
foreach (ThingICareAbout e in things.OfType<ThingICareAbout>()) { ...

我喜欢动态内容包含在访问者中 - 特别是我喜欢我甚至不需要使用Accept方法污染元素类型。特别是这意味着我们可以使用它来访问不受我们控制的类型(通常是表达式或控件)。