依赖注入

维基百科,自由的百科全书
跳转至: 导航搜索

软件工程中,依赖注入是种实现控制反转用于解决依赖性设计模式。一个依赖关系指的是可被利用的一种对象(即服务提供端) 。依赖注入是将所依赖的传递给将使用的从属对象(即客户端)。该服务是将会变成客户端的状态的一部分。 传递服务给客户端,而非允许客户端来建立或寻找服务,是本设计模式的基本要求。

范例[编辑]

假设你今天正使用 PHP 建立一个大型专案,这个时候会有许多的类别,并且互相依赖著,下面是一个登入系统的依赖注入范例。

首先这个登入系统分成三个部分,一个是验证,一个是处理工作阶段,另一个是驱动这两个的“主程式”。

传统案例[编辑]

这是一个没有使用依赖注入的传统案例。

主要程式[编辑]

这一个程式用来进行实作用途,一旦要求登入,这个主程式就会建立“验证”和“工作阶段”两个类别用以实作。

class Application
{
    function __construct($db, $dbUsername, $dbPassword)
    {
        $this->auth    = new Auth($db, $dbUsername, $dbPassword);
        $this->session = new Session();
    }
    
    function login($username, $password)
    {
        /** 詢問 Auth 驗證帳號密碼,如果正確則呼叫 Session 存入使用者帳號 */
        if($this->auth->validate($username, $password))
            $this->session->set('username', $username);
    }
}

验证[编辑]

在这里和资料库连线,并且检查帐号密码是否正确。

class Auth
{
    /** 一旦 Auth 被建立,則會建立 MySQL 資料庫 */
    function __construct($db, $dbUsername, $dbPassword)
    {
        $this->database = new MySQL($db, $dbUsername, $dbPassword);
    }
    
    /** 用來驗證帳號密碼是否和資料庫內的相符 */
    function validate($username, $password)
    {
        return $this->database->where('username', $username)
                              ->where('password', $password);
    }
}

工作阶段[编辑]

这个类别用来将使用者登入的阶段保存起来,让伺服器清楚地知道使用者登入了。

class Session
{
    function set($name, $value)
    {
        $_SESSION[$name] = $value;
    }
}

问题[编辑]

当我们实作“主程式”的时候,并不知道主程式呼叫了什么(除非我们查看主程式的原始码),

像下面这样实作就会意识到这个问题。

$application = new Application('localhost', 'root', '');

/** login() 依賴了什麼類別? */
/** 在這途中又實作了什麼類別? */
$application->login('admin', 'admin');

使用依赖注入的案例[编辑]

依赖注入的观念就是将所有东西先在“外面”准备好,然后再带入“内部”的程式中,如此一来你就能够在检视程式码的时候,一目了然地知道这个程式依赖著哪些类别。

主要程式[编辑]

现在让我们从头来过,这次“主程式”不自己实作类别,而是接受在外部建立好的类别。

class Application
{
    function __construct(Auth $auth, Session $session)
    {
        $this->auth    = $auth;
        $this->session = $session;
    }
    
    // ... 程式 ...
}

然后实作这一个登入系统像这样:

$auth        = new Auth('localhost', 'root', '');
$session     = new Session();
$application = new Application($auth, $session);

/** 嗯.. 所以我用了 Auth 跟 Session 兩個類別 */
$application->login('admin', 'admin');

这即是一个简易的依赖注入案例,但还有一些依赖的问题尚未解决,而这又牵扯到了依赖注入容器(DI Container)。