Designing fluent builders to create an object graph in C#

谁说我不能喝 提交于 2019-12-10 23:46:54

问题


I am making a first attempt at writing fluent builders in C# so I can simplify the logic for creating object graphs.

My first thought was to create a fluent builder for each class, then nest them hierarchically like this:

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()

This is straightforward to implement as a state machine using C# interfaces, and fairly easy to understand, both as a developer trying to read the code AND as a developer trying to create new code ("With*"=set a property, "Add*"=add a child object, "Save" does whatever needs to be done to create the graph), but I thought it might be easier for a developer to read and write a DSL that looks something like this:

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

Since the messages for all builders are going through the topmost parent builder object, I think I need to find some way to route them down the hierarchy to the appropriate child builder object. In Ruby this can be done with method_missing, but I can't see an smart way to implement this in C#.

An ugly solution would be to have each parent implement the interface of every potential descendent object, where each method routes its invocation to the child. Obviously this is not desirable, especially as I add more builder classes to the hierarchy, but I don't know of a concise way to "virtually" implement these interfaces at compile time but intercept all calls to that interface and proxy them down the tree, à la method_missing. I can see that there are ways to dynamically implement interfaces at runtime in C# using a dynamic proxy but I don't think any of these will support intellisense.

My requirements are that a) this works with intellisense and b) any builder can be used to build objects without reference to its parent---meaning I want all builders to be able to handle the construction of its child-builders (meaning the the ugly solution would be really ugly)

Is there a way to take this second route in C#? Or is this the wrong way to think about it?


回答1:


An alternative might be to use the object initializer syntax instead. So something like:

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

This initializes properties, so you can change the arrays into objects.



来源:https://stackoverflow.com/questions/8072492/designing-fluent-builders-to-create-an-object-graph-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!