Я бы не использовал IoC для регистрации отношений между DAO и их типами (что, в сущности, вы и делаете). Это приведет к тому, что вы будете использовать контейнер IoC в качестве «локатора службы», известного анти-паттерна, когда вы передаете контейнер IoC в объекты, которые будут использовать его для получения необходимого DAO.
Я думаю, что лучший способ упростить это с точки зрения потребления - это определить шаблон стратегии, используя фабричный класс или метод:
public Dao<T, TId> GetDaoFor<T, TId>(T objectInstance) where T:EntityWithTypedId<TId>
{
//Here, you could use a Dictionary, Linq with some reflection, etc.
}
Этот один метод может быть внедрен в качестве делегата в классы, зависящие от DAO. Разница в том, что классы, которым нужен DAO, зависят от метода, который может им их предоставить, который может быть предоставлен контейнером IoC; они НЕ зависят от самого контейнера (который является основным источником зла, присущим шаблону «поиск сервисов»). Это уменьшает количество вещей, которые вам придется изменить, если вы переписали, как вы получили эти DAO.
РЕДАКТИРОВАТЬ: Немного не по теме, но я открыл дверь:
Шаблон местоположения службы, как правило, следует избегать, поскольку он приводит к коду, который опирается на указатель службы. Например, в коде часто встречается следующее, где IoC был выставлен на дочерних уровнях:
private IDependency _dependency;
public IDependency MyDependency
{
get {
_dependency = _dependency ?? IoC.Resolve<IDependency>();
return _dependency;
}
}
Хотя это выглядит как хороший шаблон (зависимости инициализируются лениво, потребляющему коду не нужно знать о зависимостях дочернего элемента, и вы всегда * получаете ссылку), этот код ВСЕГДА будет требовать наличия синглтона IoC. Вы можете изменить структуру IoC, стоящую за ней, вы можете полностью удалить сторонний инструмент и свернуть свой собственный, но этот класс всегда будет требовать что-то, для чего статически вызывать Resolve<IDependency>()
.
Вы также НЕ ВСЕГДА получаете ссылку; Вы получите ссылку, только если вы правильно зарегистрировали IDependency в IoC. Это создает еще две слабости; 1) вы не знаете, что понадобится классу, не открывая его, и 2) если / когда вызов не удастся, он потерпит неудачу глубоко в недрах внутренней работы зависимого класса. Если вы разрабатываете новый класс и подключаете его к IoC, он может пройти интеграцию и даже некоторое время работать в производственной среде, пока не начнете получать странные ошибки «объектная ссылка установлена на ноль» в действительно странных местах кода, которые поверь мне, кошмар для отладки.
Наконец, модульное тестирование кода шаблона службы-локатора является более сложным по той простой причине, что вы должны высмеивать локатор службы, а также зависимость, предоставляемую локатором службы. Вы можете оставить локатор службы производства в рабочем состоянии и просто зарегистрировать фиктивные классы в качестве зависимостей, но это не модульный тест; Этот тест основан и, следовательно, в некоторой степени проверяет, что интеграция класса и его локатора службы работает, как ожидалось. Это интеграционный тест.
Напротив, шаблоны внедрения зависимостей освобождают вас от какой-либо зависимости от того, как разрешаются зависимости. Единственное требование (при внедрении в конструктор) - они должны присутствовать при создании класса. Это имеет несколько преимуществ:
- Если вы не используете платформу IoC, вы должны знать, что потребуется классу для его создания.
- При использовании инфраструктуры IoC вы получаете ошибку времени выполнения при попытке создания экземпляра зависимого класса, а не спустя некоторое время, когда объект фактически разрешается.
- При тестировании зависимого класса вы можете легче смоделировать зависимость, потому что зависимость не нужно вводить через локатор службы.
- В большинстве сред IoC можно по-прежнему лениво инициализировать зависимости, предоставив фабричный метод вместо фактической зависимости от конструктора. Приведенный выше шаблон затем вызывает этот делегат, который может прийти откуда угодно, вместо статического именованного метода, который удовлетворяется одной-единственной конструкцией во всей кодовой базе.