2

声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解翻译,肯定会有错误的地方,欢迎指正。

欢迎转载,转载请注明出处,谢谢!

依赖反转原则

介绍

我们来到了SOLID设计原则的最终的目标远景!它就是依赖反转原则,它是指高阶代码不能依赖低阶代码。相应的,高阶代码应该依赖一个抽象层,它是在高阶代码和低阶代码之间的“中间人”角色。另一方面,该原则指代抽象层不依赖具体实现,而是细节依赖抽象。如果这个读起来很晦涩,别担心。我们下面会对这两个方面具体的阐述本原则。

依赖反转原则 本原则是指高阶代码不依赖低阶代码,抽象不依赖具体细节。

实探

如果你已经读过本书之前的章节,就应该对依赖反转有一个很好的理解。我们通过下面例子来解释:

class Authenticator {

    public function __construct(DatabaseConnection $db)
    {
        $this->db = $db;
    }

    public function findUser($id)
    {
        return $this->db->exec('select * from users where id = ?', array($id));
    }

    public function authenticate($credentials)
    {
        // Authenticate the user...
    }

}

可以猜到,Authenticator类是负责查找并验证用户的。我们来检验下类的构造器。可以看到我们有个链接数据库的实例DatabaseConnection。所以我们将验证器和数据库紧密的接合在一起了,这意味着用户对象必须建立在关系型数据库查询之上。此外,我们的高阶代码(Authenticator类)直接依赖了低阶代码(DatabaseConnection类)。 首先,我们解释下“高阶”和“低阶”代码。低阶代码实现像这种磁盘文件访问,数据库接入等。高阶代码在低阶代码之上实现逻辑功能的封装,但不能将他们耦合进来。或者,高阶代码依赖建立在低阶代码之上的抽象层,如接口。不仅如此,低阶代码_也_依赖于抽象层。我们来实现一个可以在Authenticator类中使用的接口:

interface UserProviderInterface {
    public function find($id);
    public function findByUsername($username);
}

然后,将接口的实现注入到Authenticator

class Authenticator {

    public function __construct(UserProviderInterface $users,
    HasherInterface $hash)
    {
        $this->hash = $hash;
        $this->users = $users;
    }

    public function findUser($id)
    {
        return $this->users->find($id);
    }

    public function authenticate($credentials)
    {
        $user = $this->users->findByUsername($credentials['username']);

        return $this->hash->make($credentials['password']) == $user->password;
    }

}

这些改变之后,我们的Authenticator现在依赖两个高阶抽象:UserProviderInterfaceHasherInterface。我们就能自由的将任何针对接口的实现注入到Authenticator中了。比如,如果我们用户存储在Reids中,可以实现针对UserProvider实现一个RedisUserProvider类。Authenticator现在不在直接依赖低阶的存储操作了。 此外,自从它实现接口本身后,我们的低阶代码现在也是依赖高阶的UserProviderInterface抽象:

class RedisUserProvider implements UserProviderInterface {

    public function __construct(RedisConnection $redis)
    {
        $this->redis = $redis;
    }

    public function find($id)
    {
        $this->redis->get('users:'.$id);
    }

    public function findByUsername($username)
    {
        $id = $this->redis->get('user:id:'.$username);

        return $this->find($id);
    }

}

反转思想 很多开发人员在应用中使用_反转_原则。代替这种高阶直接耦合低阶代码的“自上而下”的方式,本原则指高阶、低阶代码“同时”依赖一个高阶抽象层。

在我们将Authenticator的依赖“倒置”前,他是无法在其他数据存储系统中使用的。在改变存储系统的情况下,必须对Authenticator进行修改,违背了开放封闭原则。我们已经知道,几种原则之间是相互贯穿的。 在将Authenticator强制实现在存储层之上的抽象层,我们可以根据UserProviderInterface接口约定切换成任意其他存储系统,而无需对Authenticator本身进行修改。传统的依赖痛过“倒置”就能事代码变得非常灵活,易于改变!


laravel
101 声望55 粉丝