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了。咱們的代碼遵循了里氏替換原則。不少建築學上的概念都被討論成一種「認知」。特別的,對於每個類,都有其本身的「語境」,他周邊的代碼在其依賴環境下幫助類來完成特定的工做。當你讓架構朝着健壯方向發展的時候,這種類的設計「認知」將是一種持久重要的主題。

當心漏洞

你也許注意到了本原則和上章中提到的迴避「抽象漏洞」相似。咱們的數據庫獲取部分就是破壞里氏替換的點,在你之後的編碼中必定要對這種編碼留心!

相關文章
相關標籤/搜索