设计模式:控制反转IoC、依赖注入DI

基本概念

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。

其中最常见的方式叫做 依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。

技术说明

Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。

采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。#

举例

下面的代码中有一个 Database的类,它需要一个适配器来与数据库交互。我们在构造函数里实例化了适配器,从而产生了耦合。

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct()
    {
        $this->adapter = new MySqlAdapter;
    }
}

class MysqlAdapter {}

上面代码产生的问题:
1、如果现在要改变 adapter 生成方式,如需要用new MySqlAdapter(String name)初始化 adapter,需要修改 Database 代码;
2、如果想测试不同 MySqlAdapter 对象对 Database 的影响很困难,因为 adapter 的初始化被写死在了 Database 的构造函数中;
3、如果new MySqlAdapter()过程非常缓慢,单测时我们希望用已经初始化好的 adapter 对象 Mock 掉这个过程也很困难。

采用依赖注入重构:

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(MySqlAdapter $adapter)
    {
        $this->adapter = $adapter;
    }
}

class MysqlAdapter {}

上面代码中,我们将 adapter 对象作为构造函数的一个参数传入。在调用 Database 的构造方法之前外部就已经初始化好了 MysqlAdapter 对象。像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。

升级版重构

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(AdapterInterface $adapter)
    {
        $this->adapter = $adapter;
    }
}

interface AdapterInterface {}

class MysqlAdapter implements AdapterInterface {}

现在 Database 类依赖于接口,相比依赖于具体实现有更多的优势。

假设你工作的团队中,一位同事负责设计适配器。在第一个例子中,我们需要等待适配器设计完之后才能单元测试。现在由于依赖是一个接口/约定,我们能轻松地模拟接口测试,因为我们知道同事会基于约定实现那个适配器

这种方法的一个更大的好处是代码扩展性变得更高。如果一年之后我们决定要迁移到一种不同的数据库,我们只需要写一个实现相应接口的适配器并且注入进去,由于适配器遵循接口的约定,我们不需要额外的重构。

发布了165 篇原创文章 · 获赞 59 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_43972437/article/details/103858533