Laravel深入學習8 – 單一責任原則

laravel發表於2019-02-16

宣告:本文並非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原汁性,另外因為是理解翻譯,肯定會有錯誤的地方,歡迎指正。

歡迎轉載,轉載請註明出處,謝謝!

單一責任原則

介紹

“SOLID”設計原則,是Robert “Uncle Bob” Martin提出的理論。它是良好應用設計的5大原則,包含:

  • 單一責任原則

  • 開放封閉原則

  • 里氏替換原則

  • 介面分離原則

  • 依賴倒置原則

讓我們通過程式碼示例來深究下這五個原則。這5個原則相互****,一榮俱榮,一毀俱毀。

實探

單一責任原則代表一個類有且僅有一個改變的原因,換言之,一個類的職責範疇是嚴謹明確的。我們之前說過對來說無知是福。類只需要幹好自己的工作,對於其依賴變化的影響是無需感知的。

看下面這個類:

class OrderProcessor {

    public function __construct(BillerInterface $biller)
    {
        $this->biller = $biller;
    }

    public function process(Order $order)
    {
        $recent = $this->getRecentOrderCount($order);

        if ($recent > 0)
        {
            throw new Exception(`Duplicate order likely.`);
        }

        $this->biller->bill($order->account->id, $order->amount);

        DB::table(`orders`)->insert(array(
            `account` => $order->account->id,
            `amount` => $order->amount;
            `created_at` => Carbon::now();
        ));
    }

    protected function getRecentOrderCount(Order $order)
    {
        $timestamp = Carbon::now()->subMinutes(5);

        return DB::table(`orders`)
            ->where(`account`, $order->account->id)
            ->where(`created_at`, `>=`, $timestamps)
            ->count();
    }

}

該類的職責是什麼?通過名字可以明確他就是來處理訂單的。但是,從getRecentOrderCount方法中又能看到該方法需要對資料庫中的歷史訂單進行檢測以判斷是否重複訂單。額外的驗證意味著在資料儲存改變的情況下,我們的訂單處理程式必須要進行驗證規則的修改。

我們可以把這個職責提取到單獨的類OrderRepository中:

class OrderRepository {

    public function getRecentOrderCount(Account $account)
    {
        $timestamp = Carbon::now()->subMinutes(5);

        return DB::table(`orders`)
        ->where(`account`, $account->id)
        ->where(`created_at`, `>=`, $timestamp)
        ->count();
    }

    public function logOrder(Order $order)
    {
        DB::table(`orders`)->insert(array(
            `account` => $order->account->id,
            `amount` => $order->amount;
            `created_at` => Carbon::now();
        ));
    }

}

然後在OrderProcessor中注入類庫,來減少它檢測賬戶歷史訂單的職責:

class OrderProcessor {

    public function __construct(BillerInterface $biller, OrderRepository $orders)
    {
        $this->biller = $biller;
        $this->orders = $orders;
    }

    public function process(Order $order)
    {
        $recent = $this->orders->getRecentOrderCount($order->account);

        if ($recent > 0)
        {
            throw new Exception(`Duplicate order likely.`);
        }

        $this->biller->bill($order->account->id, $order->amount);

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

}

現在我們將訂單資料收集責任抽象出來,當獲取記錄訂單的方法改變時,就無需再對OrderProcessor類進行修改了。現在的類庫職責明確單一,程式碼簡潔,表現力強,同時可維護性也大大的提升。

牢記,單一責任原則不是指程式碼越少越好,他是指寫類是類的職責要非常明確,要有一套可用的方法,這些方法在類中要組成類的整體職責。根據既定的職責撰寫出的這些巧而簡潔的類,我們的程式碼就能是一個解耦的,可測的,可友好改變的架構。

相關文章