MVC, DI (внедрение зависимостей) и создание экземпляра модели из контроллера - PullRequest
5 голосов
/ 09 марта 2010

Мой Диспетчер "выбирает" правильный контроллер; затем создание экземпляра контроллера (DependencyInjectionContainer передается в конструктор контроллера); затем вызывая некоторый метод контроллера ...

class UserController extends Controller
{

  public function __construct(DependencyInjectionContainer $injection) {
    $this->container = $injection;
  }

  public function detailsAction() {
    ...
  }

}

DependencyInjectionContainer содержит объект адаптера БД, объект конфигурации и т. Д. Теперь посмотрим, что содержит метод detailsAction () ...

public function detailsAction() {

  $model = new UserModel();
  $model->getDetails(12345);

}

Как видите, я создаю новый экземпляр UserModel и вызываю методы getDetails. Метод getDetails () модели должен подключаться к базе данных для получения информации о пользователе. Для подключения к БД UserModel должен иметь доступ к адаптеру БД.

Как правильно передать DependencyInjectionContainer в UserModel? Я думаю, что этот путь неправильный ...

public function detailsAction() {

  $model = new UserModel($this->container);
  $model->getDetails(12345);

}

Ответы [ 2 ]

10 голосов
/ 10 марта 2010

Вместо того, чтобы вставлять весь 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);
    }
}

Это дает вам лучшее разделение интересов .

Если вам нужно более одной зависимости, вы просто вводите их через конструктор. Когда вы начинаете получать слишком много, это признак того, что вы нарушаете Принцип единой ответственности , и пришло время реорганизовать агрегированные услуги .

0 голосов
/ 09 марта 2010

Я бы использовал одноэлементный объект для всех параметров конфигурации: Вы устанавливаете его в своем загрузочном устройстве, затем решаете использовать его напрямую или передавать в качестве параметра в своих объектах.

Идея состоит в том, чтобы иметь один метод для извлечения данных конфигурации.

Затем вы можете предоставить абстрактный класс для манипулирования БД, который использует ваш конфиг. синглтон. DependancyInjection по-прежнему может использоваться для переопределения данных по умолчанию.

Приведенная выше ссылка в комментарии (возможно, «дубликат») завершает использование инъекции конструктора: это близко к вашему текущему методу.

Однако если я попытаюсь понять, как работает ваша модель, я думаю, у вас будет много других классов моделей, кроме "userModel". Таким образом, абстрактный класс, использующий конфигурационный синглтон, может быть хорошим решением: все ваши следующие классовые модели просто расширят этот абстрактный класс, и вам не придется беспокоиться о своей конфигурации.

С другой стороны, ваше решение хорошо для меня, если ваша зависимость от инъекций часто меняется.

...