zoukankan      html  css  js  c++  java
  • [PHP-DI] 理解依赖注入

    理解依赖注入

    依赖注入依赖注入容器 是不同的:

    • 依赖注入 (Dependency injection) 是编写更好代码的一种方法
    • 容器 (Container) 是帮助注入依赖关系的工具

    你不需要一个容器来执行依赖注入,但是一个容器可以帮助你。

    PHP-DI就是这样做的:使依赖注入更加实用。

    理论

    经典的PHP代码

    下面是使用DI的代码大致工作的方式:

    • 应用程序需要 Foo(例如一个控制器),所以:
    • 应用程序创建 Foo
    • 应用程序调用 Foo
      • Foo 需要 Bar(例如一个服务),所以:
      • Foo 创建 Bar
      • Foo 调用 Bar
        • Bar 需要 Bim(一个服务,一个仓库……),所以:
        • Bar 创建 Bim
        • Bar 做一些事情

    使用依赖注入 (Dependency injection)

    下面是使用DI的代码大致工作的方式:

    • 应用程序需要 Foo ,它需要 Bar,它需要Bim,所以:
    • 应用程序创建 Bim
    • 应用程序创建 Bar 并给它 Bim
    • 应用程序创建 Foo 并给它 Bar
    • 应用程序调用 Foo
      • Foo 调用 Bar
        • Bar 做一些事情

    这是控制反转的模式,被调用者和调用者之间的依赖性控制是相反的

    最主要的优点是:在调用链顶部的那个总是。你可以控制所有依赖项,并完全控制您的应用程序的工作方式,你可以用另一个(例如你创建的一个)来替换依赖项。

    例如,如果库X使用 Logger Y,而你想让它使用 Logger Z 呢?有了依赖注入,你就不需要更改库X的代码了。

    使用容器 (Container)

    那么,使用PHP-DI的代码是如何工作的:

    • 应用程序需要 Foo,所以:
    • 应用程序从 Container 获取 Foo,所以:
      • Container 创建 Bim
      • Container 创建 Bar 并给它 Bim
      • Container 创建 Foo 并给它 Bar
    • 应用程序调用 Foo
      • Foo 调用 Bar
        • Bar 做一些事情

    简而言之,容器包含了创建和注入依赖的所有工作

    In short, the container takes away all the work of creating and injecting dependencies.

    用一个例子来理解

    这是一个真实的例子,比较了一个经典的实现(使用new或单例)和使用依赖注入。

    没有依赖注入

    假设你有:

    class GoogleMaps
    {
        public function getCoordinatesFromAddress($address) {
            // calls Google Maps webservice
        }
    }
    class OpenStreetMap
    {
        public function getCoordinatesFromAddress($address) {
            // calls OpenStreetMap webservice
        }
    }
    

    经典的做法是:

    class StoreService
    {
        public function getStoreCoordinates($store) {
            $geolocationService = new GoogleMaps();
            // or $geolocationService = GoogleMaps::getInstance() if you use singletons
    
            return $geolocationService->getCoordinatesFromAddress($store->getAddress());
        }
    }
    

    现在我们想使用OpenStreetMap而不是GoogleMaps,我们该怎么做?
    我们必须更改StoreService的代码,以及所有其他使用GoogleMaps的类。

    如果没有依赖注入,你的类与它们的依赖紧耦合。

    使用依赖注入

    StoreService 现在使用依赖注入:

    class StoreService {
        private $geolocationService;
    
        public function __construct(GeolocationService $geolocationService) {
            $this->geolocationService = $geolocationService;
        }
    
        public function getStoreCoordinates($store) {
            return $this->geolocationService->getCoordinatesFromAddress($store->getAddress());
        }
    }
    

    服务是使用接口 (Interface) 定义的:

    interface GeolocationService {
        public function getCoordinatesFromAddress($address);
    }
    
    class GoogleMaps implements GeolocationService { ...
    
    class OpenStreetMap implements GeolocationService { ...
    

    现在,StoreService的用户可以决定使用哪个实现。 它可以随时改变,不必重写StoreService

    StoreService不再与它的依赖紧耦合。

    The StoreService is no longer tightly coupled to its dependency.

    使用 PHP-DI

    你可能会发现依赖注入会带来一个缺点:你现在必须处理注入依赖关系。

    这就是容器(Container),特别是PHP-DI可以帮助你的地方。

    而不是写:

    $geolocationService = new GoogleMaps();
    $storeService = new StoreService($geolocationService);
    

    你可以写:

    $storeService = $container->get('StoreService');
    

    并配置哪个GeolocationService PHP-DI应该通过配置自动注入到StoreService中:

    $container->set('GeolocationService', DIcreate('GoogleMaps'));
    

    如果您改变主意,现在只需要改变一行配置。

    感兴趣吗? 继续阅读开始使用PHP-DI指南!

    参考

    p.s. 看到PHP-DI没有中文文档,第一次对着机翻瞎翻译,如有疏漏敬请指正。

  • 相关阅读:
    LCA模板
    bzoj1660:[Usaco2006 Nov]badhair乱头发节
    不老的传说
    田忌赛马
    最短路径问题
    hdu2421-Deciphering Password-(欧拉筛+唯一分解定理+积性函数+立方求和公式)
    hdu1215-七夕节-(埃氏筛+唯一分解定理)
    迷宫-(bfs)
    区间或和-(位运算)
    海啸-(矩阵前缀和)
  • 原文地址:https://www.cnblogs.com/warcraft/p/8733457.html
Copyright © 2011-2022 走看看