Ответ 1
Итак, как интерфейсы попадают в картину?
Вот так:
public interface IEmployeeRepository
{
Employee[] GetAll();
}
а затем вы можете иметь столько реализаций, сколько хотите:
public class EmployeeRepositoryEF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying your EF DbContext
}
}
public class EmployeeRepositoryXML: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying an XML file
}
}
public class EmployeeRepositoryWCF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying some remote WCF service
}
}
and so on ... you could have as many implementation as you like
Как вы видите, не очень важно, как мы реализуем репозиторий. Важно то, что все репозитории и реализации соответствуют определенному контракту (интерфейсу), и все обладают методом GetAll
, возвращающим список сотрудников.
И тогда у вас будет контроллер, который использует этот интерфейс.
public class EmployeesController: Controller
{
private readonly IEmployeeRepository _repository;
public EmployeesController(IEmployeeRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var employees = _repository.GetAll();
return View(employees);
}
}
Посмотрите, как контроллер больше не зависит от конкретной реализации репозитория? Все, что ему нужно знать, это то, что эта реализация соответствует контракту. Теперь все, что вам нужно сделать, - настроить вашу любимую среду инъекций зависимостей, чтобы использовать реализацию, которую вы хотите.
Вот пример того, как это делается с Ninject:
- Установите Ninject.MVC3 NuGet
-
В сгенерированном коде
~/App_Start/NinjectWebCommon.cs
вы просто решаете использовать реализацию EF с одной строкой кода:private static void RegisterServices(IKernel kernel) { kernel.Bind<IEmployeeRepository>().To<EmployeeRepositoryEF>(); }
Таким образом вам больше не нужно выполнять какие-либо ручные инстанцирования этих классов репозитория и беспокоиться о повышении или любом другом. Это управляющая среда зависимостей, которая управляет ими для вас, и позаботится о введении определенной реализации в конструктор контроллера.
И просто изменив эту конфигурацию, вы можете переключить технологию доступа к данным, не касаясь одной строки кода в контроллере. Таким образом, модульное тестирование в изоляции также вступает в игру. Поскольку ваш код контроллера теперь слабо связан с репозиторием (благодаря интерфейсу, который мы ввели), все, что вам нужно сделать в unit test, это предоставить некоторую макетную реализацию в репозитории, которая позволяет вам определить ее поведение. Это дает возможность unit test действию контроллера индекса без какой-либо зависимости от базы данных или чего-то еще. Полная изоляция.
Я также приглашаю вас проверить следующие статьи о TDD и DI в ASP.NET MVC.