Внедрение зависимостей делает невозможным отложенную загрузку зависимостей?
из-за того, что вам нужно передать экземпляры в конструктор, вы не можете сделать экземпляры позже
Внедрение зависимостей делает невозможным отложенную загрузку зависимостей?
Нет, это не делает невозможной загрузку. Я бы даже стал утверждать обратное, и я бы даже сказал, что динамические языки (такие как PHP и Ruby) делают это даже проще, чем языки со статической типизацией (такие как Java и C #).
Поскольку ваши компоненты программируются на абстракции, легко внедрить реализацию для того же контракта, который оборачивает реальную реализацию, которая может быть загружена с отложенным доступом. Обертка действует как прокси, и это позволяет потребителю не обращать внимания на тот факт, что любая ленивая загрузка происходит. Это повышает ремонтопригодность.
Мой PHP довольно ржавый, поэтому следующий пример может не быть «компилируемым» (любой PHP-разработчик, пожалуйста, не стесняйтесь обновлять этот пример), но следующее показывает идею.
Здесь мы видим некоторый класс, который реализует некоторую бизнес-логику (ShipOrderHandler
) и это зависит от зависимости логгера:
class ShipOrderHandler {
private $logger;
function __construct($logger) {
$this->logger = $logger;
}
function Handle($command) {
$this->logger->Log("shipping order " + $command->OrderId);
}
}
class DatabaseLogger {
function Log($message) {
// log the message
}
}
Вот как мы могли бы построить граф объектов для ShipOrderHandler
:
$handler = new ShipOrderHandler(new DatabaseLogger());
Не представляю DatabaseLogger
быть на самом деле тяжелым для инициализации. Используя возможности DI и динамических языков, мы можем просто добавить прокси-реализацию для нашего аннотации логгера; давай называть это LazyLogger
, Наш новый LazyLogger
может выглядеть следующим образом:
class LazyLogger {
private $loggerFactory;
private $logger;
function __construct($loggerFactory) {
$this->loggerFactory = $loggerFactory;
}
function Log($message) {
if (!$this->logger) $logger = $loggerFactory();
$this->logger.Log($message);
}
}
Теперь мы можем применить это LazyLogger
нашим Корень композиции делать DatabaseLogger
Создано лениво, без каких-либо изменений в наших компонентах приложения:
$handler = new ShipOrderHandler(
new LazyLogger(function() { return new DatabaseLogger() });
Здесь мы завернем создание DatabaseLogger
в анонимной функции, которая вводится в LazyLogger
, Когда LazyLogger
«s Log
метод вызывается впервые, фабричный метод вызывается, DatabaseLogger
создан и LazyLogger
кэширует этот экземпляр и будет использовать его до тех пор, пока он сам не выйдет из области видимости.
Как видите, Dependency Injection ни в коем случае не ограничивает использование отложенной загрузки; напротив: он позволяет ленивую загрузку без необходимости вносить радикальные изменения по всему приложению.
Это сила DI.
Вы найдете пример компонента Symfony DI в http://php.budgegeria.de/flzsbalQV2 где ленивая загрузка используется.
Класс Bar имеет зависимость от Foo, который настроен как сервис. Когда создается Foo, запускается эхо. Как видите, экземпляр будет создан, когда произойдет первый доступ к методу зависимости Foo.
Для этого вам понадобится пакет компоновщика ocramius / proxy-manager. Также возможно реализовать это ленивое поведение для других контейнеров DI.