Должен ли я использовать IoC Dedency Injector при разработке бизнес-кода?

Современные фреймворки PHP (такие как Zend, Symfony, Phalcon) используют контейнер DI, и вы просто передаете его для доступа ко всем функциям фреймворка. Мне интересно, должен ли я / мог бы использовать контейнер DI в своем бизнес-коде. Допустим, мне нужно использовать объект доступа к базе данных и объект почтовой программы, и они уже находятся в DI, потому что их использует инфраструктура. Могу ли я просто передать контейнер DI при создании бизнес-класса?

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

Но я собираюсь разработать API, который также будет использовать этот класс пользовательской модели. Так как он ожидает контейнер DI, мне нужно было бы знать заранее, каковы зависимости модели, и инициализировать контейнер DI с правильными. Раньше я просто передавал каждую зависимость в качестве параметра в конструкторе, но с IoC мне нужно было знать, не глядя на параметры, каковы зависимости класса и какое имя используется для доступа к каждой зависимости. Например, мне нужно знать, что в контейнере DI должен быть объект PDO, идентифицируемый как ‘db’. Это хороший подход для бизнес / библиотечного кода?

Я, наверное, здесь смешиваю термины, но надеюсь, вы поняли идею.

Спасибо!

3

Решение

Неважно, какой код вы разрабатываете, будь то бизнес-логика или логика фреймворка (или другой вид логики), весь смысл здесь в том, как вы справляетесь с зависимостями классов.

Семестр бизнес логика само по себе очень абстрактно. Вы можете представить бизнес-логику с помощью одного класса (a.k.a доменный объект) или вы можете представить бизнес-логику как слой.

Одна базовая вещь, которую нужно отметить: база данных — это просто механизм хранения

При разработке любого приложения вы должны помнить, что база данных может быть изменена (или вы можете перейти на решение NoSQL в будущем). И когда / если вы делаете, то $pdo больше не зависимость. Если у вас логика хранения полностью отделена от бизнес-логики, вам будет достаточно легко заменить механизм хранения. В противном случае вы переписываете много вещей, когда меняете его.

Правильно спроектированная архитектура способствует отделению логики хранилища от логики приложения. Эти шаблоны установлены в качестве лучшей практики: Data Mapper или Table Gateway

namespace Storage\MySQL;

use PDO;

abstract class AbstractMapper
{
protected $pdo;

public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
}

class UserMapper extends AbstractMapper
{
private $table = 'cms_users';

public function fetchById($id)
{
$query = sprintf('SELECT * FROM `%s` WHERE `id` =:id', $this->table);
$stmt = $this->pdo->prepare($query);
$stmt->execute(array(
':id' => $id
));

return $stmt->fetch();
}

// the rest methods that abstract table queries
}

Так что в данном случае для текущего движка хранения $pdo это базовая зависимость, и это не зависимость фреймворка или разрабатываемого вами приложения. Следующая проблема, которую вы должны решить здесь, состоит в том, как автоматизировать этот процесс прохождения $pdo зависимость от картографов. Есть только одно решение, которым вы можете воспользоваться — заводская модель

$pdo = new PDO();
$mapperFactory = new App\Storage\MySQL\Factory($pdo);

$mapperFactory->build('UserMapper'); // will return UserMapper instance with injected $pdo dependency

Теперь давайте посмотрим на очевидные преимущества:

Прежде всего, это удобочитаемость — любой, кто увидит код, поймет, что Mapper используется для абстрагирования доступа к таблице. Во-вторых, вы можете легко заменить механизм хранения (если вы планируете в будущем выполнить миграцию и добавить поддержку нескольких баз данных)

$mongo = new Mongo();
$mapperFactory = new App\Storage\Mongo\Factory($mongo);

$mapperFactory->build('UserMapper'); // will return UserMapper instance with injected $mongo dependency

Примечание. Все средства отображения для различных механизмов хранения должны реализовывать один интерфейс (применение API).

Модель не должна быть одного класса

Когда дело доходит до сети, мы в основном делаем следующее:

  • Предоставление формы (которая может выглядеть как страница контактов, форма входа и т. Д.)
  • Затем отправьте форму
  • Затем сравнивая с нашими правилами валидации
  • В случае успеха мы вставляем данные формы в механизм хранения, при ошибке мы выводим сообщения об ошибках.

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

Один из таких распространенных примеров вы можете увидеть в Yii Framework

Подходящей моделью должна быть папка классов, содержащая логику приложения (см. ZF2 или SF2).

И, наконец, стоит ли использовать DiC?

Следует ли использовать DI-контейнер при разработке кода? Хорошо, давайте посмотрим на это классический пример кода:

class House
{
public function __construct($diContainer)
{
//Let's assume that door and window have their own dependencies
// So no, it's not a Service Locator in this case
$this->door = $diContainer->getDoor();
$this->window = $diContainer->getWindow();
$this->floor = $diContainer->getFloor();
}
}

$house = new House($di)

В этом случае вы говорите, что ваш House зависит от DiC а не явно на дверях, окнах и полу. Но подождите House действительно зависит от DiC? Конечно, это не так.

И когда вы начнете тестировать свой класс, вам также придется предоставить подготовленный DiC (что совершенно не имеет значения)

Обычно люди используют контейнеры Di, чтобы избежать инъекций все время. Но с другой стороны, это требует некоторой оперативной памяти и некоторого времени для анализа, так как большинство DI-контейнеров основаны на конфигурации.

Хорошая архитектура может быть свободна от любого контейнера Di, поскольку она использует преимущества фабрики и SRP.

Поэтому хорошие компоненты приложения не должны содержать никаких сервисных локаторов и контейнеров Di.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]