Недавно я начал читать об инъекции зависимостей, и он заставил меня переосмыслить некоторые из моих проектов.
Проблема у меня есть что-то вроде этого: Скажем, у меня есть два класса: автомобиль и пассажир; Для этих двух классов у меня есть некоторые данные для работы с базой данных: CarDataMapper и PassengerDataMapper
Я хочу иметь возможность сделать что-то вроде этого в коде:
$car = CarDataMapper->getCarById(23); // returns the car object
foreach($car->getPassengers() as $passenger){ // returns all passengers of that car
$passenger->doSomething();
}
Прежде чем я узнал что-нибудь о DI, я бы построил свои классы следующим образом:
class Car {
private $_id;
private $_passengers = null;
public function getPassengers(){
if($this->_passengers === null){
$passengerDataMapper = new PassengerDataMapper;
$passengers = $passengerDataMapper->getPassengersByCarId($this->getId());
$this->setPassengers($passengers);
}
return $this->_passengers;
}
}
У меня также был бы аналогичный код в методе Passenger- > getCar() для извлечения автомобиля, в котором находится пассажир.
Теперь я понимаю, что это создает зависимости (ну, я тоже это понял), но я не знал, что это "неправильно" ) между объектами "Автомобиль" и "Пассажир" и объектами отображения данных.
При попытке думать о решении для этих двух вариантов мне пришло в голову, но мне не очень-то нравится:
1: Выполнение примерно так:
$car = $carDataMapper->getCarById(23);
$passengers = $passengerDataMapper->getPassengersByCarId($car->getId());
$car->setPassengers($passengers);
foreach($car->getPassengers() as $passenger){
$passenger->doSomething();
}
Но что делать, если у пассажиров есть объекты, которые им нужно вводить, и что, если вложенность идет до десяти или двадцати уровней... Я бы включил экземпляр почти каждого объекта в начале моего приложения, что в свою очередь запросило бы весь базы данных во время процесса. Если я должен отправить пассажира другому объекту, который должен что-то сделать с объектами, которые удерживает пассажир, я не хочу немедленно создавать эти объекты тоже.
2: Внедрение карт данных в автомобильные и пассажирские объекты и что-то вроде этого:
class Car {
private $_id;
private $_passengers = null;
private $_dataMapper = null;
public function __construct($dataMapper){
$this->setDataMapper($dataMapper);
}
public function getPassengers(){
if($this->_passengers === null && $this->_dataMapper instanceof PassengerDataMapper){
$passengers = $this->_dataMapper->getPassengersByCarId($this->getId());
$this->setPassengers($passengers);
}
return $this->_passengers;
}
}
Мне не нравится это лучше, потому что это не похоже на то, что автомобиль действительно не знает о карте данных, и без устройства отображения данных автомобиль может вести себя непредсказуемо (не возвращая пассажиров, когда они на самом деле есть)
Итак, мой первый вопрос: Я принимаю совершенно неправильный подход здесь, потому что, чем больше я смотрю на него, тем больше похоже, что я строю ORM вместо бизнес-уровня?
Второй вопрос: есть ли способ фактического развязывания объектов и карт данных таким образом, чтобы я мог использовать объекты, как описано в самом первом блоке кода?
Третий вопрос: Я видел некоторые ответы на другие языки (например, какая-то версия C), разрешая эту проблему с чем-то вроде описанного здесь: Каков правильный способ ввода зависимости доступа к данным для ленивой загрузки? Поскольку у меня не было времени играть на других языках, для меня это не имеет смысла, поэтому я был бы признателен, если бы кто-нибудь объяснил примеры в ссылке в PHP-ish.
Я также рассмотрел некоторые рамки DI и прочитал о DI Containers и Inversion of Control, но из того, что я понял, они используются для определения и ввода зависимостей для "нединамических" классов, где, например, Car будет зависеть на двигателе, но ему не нужно, чтобы двигатель динамически загружался из db, он просто был бы создан и инъецирован в автомобиль.
Извините за длинный пост и спасибо заранее.