Внедрение зависимостей аргументов, известных во время выполнения? - PullRequest
2 голосов
/ 11 февраля 2011

Я уже давно использую контейнеры IoC, но сегодня я обнаружил, что в коде снова и снова появляется некий «шаблон». Чтобы дать вам некоторое представление, я сейчас работаю над веб-приложением, которое в основном используется для анализа данных. Там есть набор функций, которые требуют от пользователя подобрать то, что мы называем QueryTypeContex в самом начале. После выбора этого типа запроса могут быть предприняты другие шаги, но все они выполняются в этом конкретном QueryTypeContex. В графическом интерфейсе пикап QueryTypeContex представлен как новая вкладка с другими элементами управления.

Когда пользователь работает с данным QueryTypeContex, все ajax-вызовы на сервер включают QueryTypeId, который идентифицирует выбор пользователя и используется для построения QueryTypeContex на сервере, который затем используется для различного извлечения и обработки данных.

Я обнаружил, что многие из наших контроллеров (мы используем asp.net mvc), которые созданы с использованием контейнера Ioc, имеют одну общую черту. Есть метод действия, который выглядит примерно так:

public class AttributeController : Controller 
{
  public AttributeController(IUsefulService usefulService)
  {
     _usefulservice = usefulService;
  }
  ActionResult GetAttributes(QueryTypeContex context)
  {
    var dataDto = _usefulService.Manipulate(context, currentUser);
    return JSon(dataDto);
  }
  ...
}

Чтобы связать QueryTypeContex с аргументом действия, мы используем привязку пользовательской модели, которая извлекает некоторую информацию из базы данных. Как только служба получает QueryTypeContex в качестве аргумента, она передает ее или ее свойства своим соавторам в аргументах метода для уровня доступа к данным экземпляра. И вот есть фабричный класс, который выглядит так

public interface IDateValueFactory 
{
   DateValue CurrentYear(QueryTypeContex context);
   DateValue RollingMonth(int numberOfMonths, QueryTypeContex context);
   DateValue RollingQuareter(int numberOfQuarters, QueryTypeContex context);
}

public class DateValueFactory : IDateValueFactory 
{
  public DateValueFactory(IDateValueDb dateValueDb)
  {
    _dateValueDb = dateValueDb;
  }

  public DateValue CurrentYear(QueryTypeContext context)
  {
    var currentYear = _dateValueDb.GetCurrentYear(context.Id);
    return new DateValue(DateValueType.CurrentYear, currentYear, context);
  }

  public DateValue RollingMonth(int numberOfMonths, QueryTypeContex context)
  {
    return new DateValue(DateValueType.RollingMonth, numberOfMonths, context);
  }
  ...

}

Как вы видите, все эти методы получают QueryTypeContex в качестве параметра, что более важно , все они получают один и тот же экземпляр QueryTypeContex в течение своей короткой жизни (один веб-запрос). Поэтому я начал задаваться вопросом, могу ли я реорганизовать это так, чтобы всякий раз, когда многие методы класса обслуживания требовали QueryTypeContex в качестве аргументов, они вводились бы через конструктор, а не передавали одно и то же значение снова и снова. Например:

public interface IDateValueFactory 
{
   DateValue CurrentYear();
   DateValue RollingMonth(int numberOfMonths);
   DateValue RollingQuareter(int numberOfQuarters);
}

public class DateValueFactory : IDateValueFactory 
{
  public DateValueFactory(IDateValueDb dateValueDb, QueryTypeContext context)
  {
    _dateValueDb = dateValueDb;
    _context = context;
  }

  public DateValue CurrentYear()
  {
    var currentYear = _dateValueDb.GetCurrentYear(_context.Id);
    return new DateValue(DateValueType.CurrentYear, currentYear, _context);
  }

  public DateValue RollingMonth(int numberOfMonths)
  {
    return new DateValue(DateValueType.RollingMonth, numberOfMonths, _context);
  }
  ...

}

А теперь реальный вопрос: Это хорошая идея для такого рода вещей или это нарушает некоторые принципы дизайна, которых я должен придерживаться?

Чтобы внедрить экземпляр QueryTypeContex, созданный с использованием информации из http-запроса, я подумал о встраивании QueryTypeId в uris, чтобы он был доступен в RouteData на сервере. Затем, перед созданием контроллера, я мог бы вытащить его, собрать QueryTypeContex, создать вложенный контейнер IoC для этого запроса и вставить его в контейнер. Тогда всякий раз, когда некоторому классу потребуется QueryTypeContex для выполнения своей работы, он просто объявляет его как аргумент конструктора.

1 Ответ

5 голосов
/ 12 февраля 2011

Все, что вы можете толкать конструктору как зависимости, вы должны.Зависимости, связанные с внедрением в конструктор: детали реализации , тогда как параметры метода являются частью API модели .

Рефакторизовать зависимости, проводимые через конструкторы, гораздо проще, чем изменятьAPI, поэтому для удобства сопровождения вы должны предпочитать как можно меньше параметров метода.

...