C# 设计fluent构建器在C语言中创建对象图#
我第一次尝试用C#编写fluent构建器,以便简化创建对象图的逻辑 我的第一个想法是为每个类创建一个fluent构建器,然后像这样分层嵌套它们:C# 设计fluent构建器在C语言中创建对象图#,c#,interface,fluent,C#,Interface,Fluent,我第一次尝试用C#编写fluent构建器,以便简化创建对象图的逻辑 我的第一个想法是为每个类创建一个fluent构建器,然后像这样分层嵌套它们: School school = SchoolBuilder.New() .WithName("Whatchamatta U") .AddClass( ClassBuilder.New() .WithName("Arithmetic") .WithClassNumber("101") .AddStu
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()
School school = SchoolBuilder.New()
.WithName("Whatchamatta U")
.AddClass()
.WithClassName("Arithmetic")
.WithClassNumber("101")
.AddStudent()
.WithStudentName("John Smith")
.AddStudent()
.WithStudentName("Jane Smith")
.Save()
这很容易实现为使用C#接口的状态机,并且相当容易理解,无论是作为试图阅读代码的开发人员,还是作为试图创建新代码的开发人员(“With*”=设置属性,“Add*”=添加子对象,“Save”执行创建图形所需的任何操作),但我认为,对于开发人员来说,阅读和编写类似于以下内容的DSL可能更容易:
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()
School school = SchoolBuilder.New()
.WithName("Whatchamatta U")
.AddClass()
.WithClassName("Arithmetic")
.WithClassNumber("101")
.AddStudent()
.WithStudentName("John Smith")
.AddStudent()
.WithStudentName("Jane Smith")
.Save()
由于所有构建器的消息都经过最顶层的父构建器对象,因此我认为需要找到某种方法将它们沿层次结构向下路由到相应的子构建器对象。在Ruby中,这可以通过缺少方法来实现,但我看不到在C中实现这一点的聪明方法
一个丑陋的解决方案是让每个父对象实现每个潜在子对象的接口,其中每个方法将其调用路由到子对象。显然,这是不可取的,尤其是当我向层次结构中添加更多的构建器类时,但我不知道有什么简洁的方法可以在编译时“虚拟”实现这些接口,而是截获对该接口的所有调用并将其代理到树下,就像方法一样。我可以看到,有一些方法可以在运行时使用动态代理在C#中动态实现接口,但我认为这些方法都不支持intellisense
我的要求是a)这适用于intellisense,b)任何构建器都可以在不参考其父构建器的情况下构建对象——这意味着我希望所有构建器都能够处理其子构建器的构建(这意味着丑陋的解决方案将非常丑陋)
有没有办法在C#走第二条路线?或者这是一种错误的思考方式吗?另一种方法可能是使用语法。比如:
School school = new School {
Name = "Watchamatta U",
Classes = new[] {
new Class {
Name = "Arithmetic",
Number = "101",
Students = new[] {
// etc.
}
}
}
};
这会初始化属性,因此您可以将数组更改为对象。我通过添加
new[]
(推断数组类型)和放弃默认构造函数参数(在C中使用对象初始化器时是可选的)为您清理了它。谢谢,这是一个很好的选择——对象初始值设定项和新的4.0参数默认值肯定会使这一点变得非常清晰。但我仍在努力弄清楚这样一个流畅的界面在C#中是否可行。在花了一些时间之后,我认为#2不是一个好主意,尽管它很干净。我使用C#pseudo mixin思想实现了一个“主控制器”——每个类都有自己的构建器mixin——认为无论我从哪个级别开始,我都可以将所有命令路由到该级别(即,我可以从ClassBuilder.new()开始)。这是可行的,但只有创造性地使用泛型,例如..AddClass(),这使得语法非常难看。另一个缺点是,您会遇到各种名称冲突。我有一份工作,而且简单多了。