Проектирование беглых строителей для создания графа объектов в C # - PullRequest
2 голосов
/ 10 ноября 2011

Я делаю первую попытку написания свободно работающих конструкторов на 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 #? Или это неправильный способ думать об этом?

1 Ответ

4 голосов
/ 10 ноября 2011

Альтернативой может быть использование вместо этого синтаксиса инициализатора объекта *1001*. Так что-то вроде:

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

Это инициализирует свойства, поэтому вы можете изменять массивы на объекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...