Laravel深刻学习10 - 里氏替换原则

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

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

里氏替换原则

简介

别担忧,里氏替换原则实际上比他的名字好理解。他是指任何在任何接受抽象化类的地方其实现也被接受。通俗的讲,类中使用接口实现的地方,不须要修改代码对于任意的接口实现类都将能使用。this

里氏替换原则编码

该原则表示,程序中对于实例化对象的子类型,不须要修改代码,能够直接进行替换。翻译

实探

咱们继续拿OrderProcessor举例来阐述该原则,看下这个方法:设计

public function process(Order $order)
{
    // Validate order...

    $this->orders->logOrder($order);
}

Order验证以后,咱们使用OrderRepositoryInterface接口实现类来记录订单日志。咱们假定,当订单处理未成熟时,咱们将全部的订单以CSV格式记录到系统中。咱们的额OrderRepositoryInterface接口实现类为CsvOrderRepository。当业务继续发展,咱们想使用关系型数据库记录订单。下面,咱们看下一种可能的接口实现:日志

class DatabaseOrderRepository implements OrderRepositoryInterface {

    protected $connection;

    public function connect($username, $password)
    {
        $this->connection = new DatabaseConnection($username, $password);
    }

    public function logOrder(Order $order)
    {
        $this->connection->run('insert into orders values (?, ?)', array(
            $order->id, $order->amount,
        ));
    }

}

如今,让咱们检验下如何将不得不去使用此实现:code

public function process(Order $order)
{
    // Validate order...

    if ($this->repository instanceof DatabaseOrderRepository)
    {
        $this->repository->connect('root', 'password');
    }

    $this->repository->logOrder($order);
}

注意,在订单处理类中,咱们强制检测了OrderRepositoryInterface是否为一个数据库的实现方式。若是是,继续数据库的链接。在小型应用中还算是小问题,可是,若是在不少其余类中OrderRepositoryInterface被使用到时怎么办?咱们就只能在全部地方去添加这段“引导”代码。这样的代码维护让人头痛,还会代码潜在的bug,若是有一个地方忘记修改,就瞎了。对象

上述实例已违背里氏替换原则。在不修改connect方法的状况下咱们没法注入接口的实现类。既然发现了问题,那就去修复他们吧。这里是一个新的DatabaseOrderRepository实现类:接口

class DatabaseOrderRepository implements OrderRepositoryInterface {

    protected $connector;

    public function __construct(DatabaseConnector $connector)
    {
        $this->connector = $connector;
    }

    public function connect()
    {
        return $this->connector->bootConnection();
    }

    public function logOrder(Order $order)
    {
        $connection = $this->connect();

        $connection->run('insert into orders values (?, ?)', array(
            $order->id, $order->amount,
        ));
    }

}

如今在DatabaseOrderRepository中实现了数据库链接的管理,咱们就能够从OrderProcessor中移除那段“引导”代码了:

public function process(Order $order)
{
    // Validate order...

    $this->repository->logOrder($order);
}

如此改变,咱们就能够在OrderProcessor中随意使用CsvOrderRepository或者DatabaseOrderRepository了。咱们的代码遵循了里氏替换原则。不少建筑学上的概念都被讨论成一种“认知”。特别的,对于每个类,都有其本身的“语境”,他周边的代码在其依赖环境下帮助类来完成特定的工做。当你让架构朝着健壮方向发展的时候,这种类的设计“认知”将是一种持久重要的主题。

当心漏洞

你也许注意到了本原则和上章中提到的回避“抽象漏洞”相似。咱们的数据库获取部分就是破坏里氏替换的点,在你之后的编码中必定要对这种编码留心!

相关文章
相关标签/搜索