Я недавно начал читать о внедрении зависимостей, и это заставило меня переосмыслить некоторые из моих проектов.
У меня проблема примерно такая: допустим, у меня есть два класса: Car и Passenger;Для этих двух классов у меня есть несколько картографов данных для работы с базой данных: 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 будетзависит от двигателя, но для него не требуется, чтобы двигатель загружался динамически из БД, он просто был бы создан и внедрен в машину.
Извините за длинный пост и заранее спасибо.