Мой Диспетчер "выбирает" корректный Контроллер; затем создавая экземпляр Контроллера (DependencyInjectionContainer передается конструктору Controller); затем называя метод некоторого Контроллера...
class UserController extends Controller
{
public function __construct(DependencyInjectionContainer $injection) {
$this->container = $injection;
}
public function detailsAction() {
...
}
}
DependencyInjectionContainer содержит объект адаптера DB, Объект конфигурации и т.д. Теперь давайте посмотрим, какой detailsAction () метод содержит...
public function detailsAction() {
$model = new UserModel();
$model->getDetails(12345);
}
Поскольку Вы видите, что я создаю новый экземпляр UserModel и называю getDetails методы. getDetails модели () метод должен соединиться с дб для получения информации о пользователе. Для соединения с DB, UserModel должен смочь получить доступ к адаптеру DB.
Что правильный путь состоит в том, чтобы передать DependencyInjectionContainer UserModel? Я думаю, что этот путь является неправильным...
public function detailsAction() {
$model = new UserModel($this->container);
$model->getDetails(12345);
}
Вместо того, чтобы внедрять весь контейнер DI в свои классы, вы должны внедрить только те зависимости , которые вам нужны.
Вашему UserController требуется адаптер БД (назовем этот интерфейс IDBAdapter). В C # это может выглядеть так:
public class UserController
{
private readonly IDBAdapter db;
public UserController(IDBAdapter db)
{
if (db == null)
{
throw new ArgumentNullException("db");
}
this.db = db;
}
public void DetailsAction()
{
var model = new UserModel(this.db);
model.GetDetails(12345);
}
}
В этом случае мы внедряем зависимость в UserModel. В большинстве случаев, однако, я склонен считать это запахом DI, если UserController принимает зависимость только для передачи его, поэтому лучшим подходом может быть использование UserController зависимости от абстрактной фабрики, подобной этой:
public interface IUserModelFactory
{
UserModel Create();
}
В этом варианте UserController может выглядеть так:
public class UserController
{
private readonly IUserModelFactory factory;
public UserController(IUserModelFactory factory)
{
if (factory == null)
{
throw new ArgumentNullException("factory");
}
this.factory = factory;
}
public void DetailsAction()
{
var model = this.factory.Create();
model.GetDetails(12345);
}
}
, и вы можете определить конкретный UserModelFactory, который зависит от IDBAdapter:
public class UserModelFactory : IUserModelFactory
{
private readonly IDBAdapter db;
public UserModelFactory(IDBAdapter db)
{
if (db == null)
{
throw new ArgumentNullException("db");
}
this.db = db;
}
public UserModel Create()
{
return new UserModel(this.db);
}
}
Это дает вам лучшее разделение задач .
Если вам нужно более одной зависимости, вы просто вставляете их через конструктор. Когда вы начинаете получать слишком много, это признак того, что вы нарушаете Принцип единой ответственности , и пришло время провести рефакторинг до Aggregate Services .
Я бы использовал одноэлементный объект для всех параметров конфигурации: Вы настраиваете его в начальной загрузке, а затем решаете использовать его напрямую или передаете как параметр в ваших объектах.
Идея состоит в том, чтобы иметь один метод для извлечения данных конфигурации.
Затем вы можете предоставить абстрактный класс для манипуляций с базой данных, который использует вашу конфигурацию. singleton. DependancyInjection все еще можно использовать для переопределения данных по умолчанию.
Приведенная выше ссылка в комментарии (возможный «дубликат») завершает использование внедрения конструктора: это близко к вашему текущему методу.
Однако, если я попытаюсь понять, как работает ваша модель, я думаю, у вас будет много других классов моделей, кроме userModel. Таким образом, абстрактный класс, использующий синглтон конфигурации, может быть хорошим решением: все ваши следующие классы моделей будут просто расширять этот абстрактный класс, и вам не нужно беспокоиться о своей конфигурации.
С другой стороны, ваше решение хорошо для меня, если ваш зависимый InjectionContainer часто меняется.