聲明:本文並不是博主原創,而是來自對《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
了。咱們的代碼遵循了里氏替換原則。不少建築學上的概念都被討論成一種「認知」。特別的,對於每個類,都有其本身的「語境」,他周邊的代碼在其依賴環境下幫助類來完成特定的工做。當你讓架構朝着健壯方向發展的時候,這種類的設計「認知」將是一種持久重要的主題。
當心漏洞
你也許注意到了本原則和上章中提到的迴避「抽象漏洞」相似。咱們的數據庫獲取部分就是破壞里氏替換的點,在你之後的編碼中必定要對這種編碼留心!