c# - C# 中的用户可扩展访问者模式

标签 c# visitor-pattern

是否可以在 C# 中创建用户可扩展的访问者模式? (最好是 .net 3.5)

我在库中有一组类,我希望通过访问者模式向它们添加功能。问题是库的用户也可以创建自己的类。这意味着您需要创建一个特殊的访问者来接受新的类类型,但我们的 Accept 方法设置为接收基类型。如何让派生类在派生访问者中调用正确的方法。

或者是否有另一种方法可以做到“如果是这种类型,就这样做”?

一些示例代码:

/* In library */
namespace VisitorPattern.System
{
   interface IThing
   {
      void Accept(SystemVisitor visitor);
      void ThingMethodA(...);
      void ThingMethodB(...);
   }

   class SystemThingA : IThing
   {
      public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
      ...ThingMethods...
   }
   class SystemThingB : IThing
   {
      public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
      ...ThingMethods...
   }
   class SystemThingC : IThing
   {
      public void Accept(SystemVisitor visitor) { visitor.Visit(this); }
      ...ThingMethods...
   }

   class SystemVisitor
   {
      public SystemVisitor(object specialSystemServices) { }
      public virtual void Visit(SystemThingA thing) { Console.WriteLine("SystemThingA"); }
      public virtual void Visit(SystemThingB thing) { Console.WriteLine("SystemThingB"); }
      public virtual void Visit(SystemThingC thing) { Console.WriteLine("SystemThingC"); }
      public virtual void Visit(IThing thing) { Console.WriteLine("sysvis:IThing"); }
   }
}

/* in user code */
namespace VisitorPattern.User
{
   using VisitorPattern.System;

   class UserThingA : IThing
   {
      public void Accept(SystemVisitor visitor)
      {
         var userVisitor = visitor as UserVisitor; 
         if (userVisitor == null) throw new ArgumentException("visitor"); 
         userVisitor.Visit(this);
      }
      ...ThingMethods...
   }
   class UserThingB : IThing
   {
      public void Accept(SystemVisitor visitor)
      {
         var userVisitor = visitor as UserVisitor;
         if (userVisitor == null) throw new ArgumentException("visitor");
         userVisitor.Visit(this);
      }
      ...ThingMethods...
   }
   class UserThingC : IThing
   {
      public void Accept(SystemVisitor visitor)
      {
         var userVisitor = visitor as UserVisitor;
         if (userVisitor == null) throw new ArgumentException("visitor");
         userVisitor.Visit(this);
      }
      ...ThingMethods...
   }

   // ?????
   class UserVisitor : SystemVisitor
   {
      public UserVisitor(object specialSystemServices, object specialUserServices) : base(specialSystemServices) { }

      public void Visit(UserThingA thing) { Console.WriteLine("UserThingA"); }
      public void Visit(UserThingB thing) { Console.WriteLine("UserThingB"); }
      public void Visit(UserThingC thing) { Console.WriteLine("UserThingC"); }
      public override void Visit(IThing thing) { Console.WriteLine("uservis:IThing"); }
   }

   class Program
   {
      static void Main(string[] args)
      {
         var visitor = new UserVisitor("systemservice", "userservice");
         List<IThing> mylist = new List<IThing> { new UserThingA(), new SystemThingB(), new SystemThingC(), new UserThingC() };
         foreach (var thing in mylist)
         {
            thing.Accept(visitor);
         }
      }
   }
}

最佳答案

看来你把这一切都弄反了。首先,让我们谈谈里氏替换原则。它说任何类型都应该可以被基本类型替换。这也适用于访问者模式。

如果您有一个名为 void Accept(IVisitor visitor) 的方法,则访问的是 FancyVisitor 还是 SipleVisitor 应该无关紧要.

访问者模式的整体思想是主题(即被访问的类)除了访问者实现的契约(基类或接口(interface))之外,不应该知道任何关于访问者的信息.每个 Visitor 类都应该特定于被访问的特定类。

这就是您的代码存在的问题。您正在尝试创建一个可以访问所有系统组件的通用 Visitor 类。这是完全错误的。

在我看来,您有两个选择:

您想从所有系统组件收集相同类型的信息。

简单。创建所有系统组件实现的新接口(interface)。然后将访问者更改为 Visit(ISystemCompoent subject)

您想从每个系统组件收集不同种类的信息

然后您需要创建不同的访问者基类(或接口(interface))。

关于c# - C# 中的用户可扩展访问者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6302410/

相关文章:

c# - 持久资源管理器 (IEnlistmentNotification) 恢复

c# - 使用 KMS 加密的 S3 PutObject 失败并出现 403 "Access Denied"错误

c# - 正则表达式 - 删除跨越多个换行符的 HTML 注释

C++17 构建两侧具有变体的运算符的最佳方法?

java - 任何面向对象的灵活 Java x86 反汇编程序库?

c# - 如何在特定属性上使用 Distinct 并根据谓词选择要保留的对象?

c# - C++ 列表与 C# 列表等效

c# - API 中的访问者模式有什么好处?

c# - 在不知道 C# 类名称的情况下转换为基类

c# - Stateful Expression 访问者多次运行问题