30 июля 2011 г.

Загрузка связей по требованию в StructureMap: продолжение

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

Если у вас доменная модель основана на интерфейсах, то у вас неминуемо возникнет проблема истанцирования реальных объектов в методах сервисов. Давайте я поясню это на примере. Представим, что у нас есть класс User, который имплементирует интерфейс IUser. Везде в коде мы используем IUser и это нас вполне устраивает. Но определенно в каком-нибудь месте системы эти объекты User должны создаваться. Код может быть примерно такой:

public IUser CreateUser(string userName, string userPassword)
{
  IUser user = StructureMap.ObjectFactory.GetInstance< IUser >();
  user.Name = userName;
  user.Password = userPassword;

  return user;
}

Проблема этого кода в том, что такой код неудобно тестировать. Вам придется мокировать Factory, чтобы создать нужного юзера.

Альтернативным подходом будет передавать в конструктор Func, который бы резолвился автоматически StructureMap. Когда код можно было бы переписать так:

public IUser CreateUser(string userName, string userPassword)
{
  IUser user = this.getUser(); // поле класса типа Func< IUser >
  user.Name = userName;
  user.Password = userPassword;

  return user;
}

На мой взгляд, такой код обладает одним неоспоримым плюсом: его легче протестировать, потому что достаточно передать в конструктор сервиса что-то типа delegate() { return new User(); } и никаких сложных настроек мок-объектов не понадобится. Очевидным минусом такого подхода является то, что конструктор сервиса захламляется не нужным делегатом.

А что вы думаете на этот счет?

2 комментария: