Недавно я начал читать о внедрении зависимостей, и это заставило меня переосмыслить некоторые из моих разработок.
Проблема у меня примерно такая:Скажем, у меня есть два класса:Автомобиль и Пассажир; Для этих двух классов у меня есть несколько преобразователей данных для работы с базой данных :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()для получения автомобиля, в котором находится пассажир.
Теперь я понимаю, что это создает зависимости (ну, я понял это раньше тоже, но я не знал, что это "неправильно")между объектами Car и Passenger и объектами преобразователя данных.
При попытке придумать решение для этого пришло на ум два варианта, но мне не очень нравится ни один из них:
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-контейнерах и инверсии управления, но насколько я понял, они используются для определения и внедрения зависимостей для «нединамических» классов, где, например, Car будет зависеть на двигателе, но для этого не потребуется динамическая загрузка движка из базы данных, он будет просто создан и введен в автомобиль.
Извините за длинное сообщение и заранее спасибо.