Я делаю первую попытку написания свободно работающих конструкторов на 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 #.
Уродливое решение состояло бы в том, чтобы каждый родительский элемент реализовывал интерфейс каждого потенциального объекта-потомка, где каждый метод направляет свой вызов дочернему объекту. Очевидно, что это нежелательно, тем более что я добавляю больше классов построителя в иерархию, но я не знаю краткого способа «виртуальной» реализации этих интерфейсов во время компиляции, но перехватывать все вызовы этого интерфейса и проксировать их в дереве а ля method_missing. Я вижу, что существуют способы динамической реализации интерфейсов во время выполнения в C # с использованием динамического прокси, но я не думаю, что какой-либо из них будет поддерживать intellisense.
Мои требования состоят в том, чтобы: а) это работало с intellisense и б) любой конструктор мог использоваться для построения объектов без ссылки на его родительский элемент - это означает, что я хочу, чтобы все компиляторы могли обрабатывать конструкцию своих дочерних компоновщиков ( это означает, что уродливое решение будет действительно безобразно)
Есть ли способ пойти по этому второму маршруту в C #? Или это неправильный способ думать об этом?