设计流畅的构建器以在C#中创建对象图

时间:2011-11-09 22:12:49

标签: c# interface fluent

我正在尝试用C#编写流畅的构建器,这样我就可以简化创建对象图的逻辑。

我的第一个想法是为每个类创建一个流畅的构建器,然后按层次结构嵌套它们:

School school = SchoolBuilder.New()
  .WithName("Whatchamatta U")
  .AddClass(
      ClassBuilder.New()
      .WithName("Arithmetic")
      .WithClassNumber("101")
      .AddStudent(
         StudentBuilder.New()
         .WithName("John Smith")
      )
      .AddStudent(
         StudentBuilder.New()
         .WithName("Jane Smith")
      )
  )
  .Save()

这很容易实现为使用C#接口的状态机,并且相当容易理解,作为开发人员尝试读取代码和作为开发人员尝试创建新代码(“With *”=设置属性, “添加*”=添加子对象,“保存”执行创建图表所需的任何操作),但我认为开发人员可能更容易读取和编写看起来像这样的DSL:

School school = SchoolBuilder.New()
  .WithName("Whatchamatta U")
  .AddClass()
    .WithClassName("Arithmetic")
    .WithClassNumber("101")
    .AddStudent()
       .WithStudentName("John Smith")
    .AddStudent()
       .WithStudentName("Jane Smith")         
  .Save()

由于所有构建器的消息都通过最顶层的父构建器对象,我认为我需要找到一些方法将它们沿着层次结构路由到相应的子构建器对象。在Ruby中,这可以通过method_missing来完成,但我看不到在C#中实现它的智能方法。

一个丑陋的解决方案是让每个父实现每个可能的后代对象的接口,其中每个方法将其调用路由到子进程。显然这是不可取的,特别是当我向层次结构中添加更多构建器类时,但我不知道在编译时“虚拟”实现这些接口的简洁方法,但是拦截对该接口的所有调用并将它们代理到树中,àlamethod_missing。我可以看到有很多方法可以在C#中使用动态代理在运行时动态实现接口,但我认为其中任何一个都不支持intellisense。

我的要求是:a)这适用于intellisense和b)任何构建器都可以用来构建对象而不参考其父级 - 这意味着我希望所有构建器能够处理其子构建器的构造(意思是丑陋的解决方案真的丑陋)

有没有办法在C#中使用第二条路线?或者这是错误的思考方式吗?

1 个答案:

答案 0 :(得分:4)

另一种方法可能是使用object initializer语法。如下所示:

School school = new School {
    Name = "Watchamatta U",
    Classes = new[] {
        new Class {
            Name = "Arithmetic",
            Number = "101",
            Students = new[] {
                // etc.
            }
        }
    }
};

这会初始化属性,因此您可以将数组更改为对象。