上一篇php
The "SOLID" design principles, articulated by Robert "Uncle Bob" Martin, are five principles that provide a good foundation for sound application design. The five principles are:數據庫
羅伯特「鮑勃叔叔」馬丁闡述了名爲「堅實」的一些設計原則(譯者注:看下面五個原則的首字母正是 SOLID)。這些都是製做完善的程序設計的優秀基礎,一共有五個原則:express
Let's explore each of these principles in more depth, and look at some code examples illustrating each principle. As we will see, each principle compliments the others, and if one principle falls, most, if not all, of the others do as well.app
讓咱們深刻探索一下,再看點代碼樣例來講明各個原則。咱們將看到,每一個原則之間都有聯繫。若是其中一個原則沒有被遵循,那麼其餘大部分(可能不會是所有)的原則也會出問題。less
The Single Responsibility Principle states that a class should have one, and only one, reason to change. In other words, a class' scope and responsibility should be narrowly focused. As we have said before, ignorance is bliss when it comes to class responsibilities. A class should do its job, and should not be affected by changes to any of its dependencies.ide
單一職責原則規定一個類有且僅有一個理由使其改變。換句話說,一個類的功能邊界和職責應當是十分狹窄且集中的。咱們以前就提到過,在類的職責問題上,無知是福。一個類應當作它該作的事兒,而且不該當被它的依賴的任何變化所影響到。函數
Consider the following class:測試
考慮下列類:ui
<!-- lang: php --> 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(); } }
What are the responsibilities of the class above? Obviously, its name implies that it is responsible for processing orders. But, based on the getRecentOrderCount
method, we can also see that it is responsible for examining an account's order history in the database in order to detect duplicated orders. This extra validation responsibility means that we must change our order processor when our data store changes, as well as when our order validation rules change.this
上面這個類的職責是什麼?很顯然顧名思義,它是用來處理訂單的。不過因爲getRecentOrderCount
這個方法的存在,這個類就有了在數據庫中審查某賬號訂單歷史來看有沒有重複訂單的職責。這個額外的驗證職責意味着當咱們的存儲方式改變或當訂單驗證規則改變時,咱們的這個訂單處理器也要跟着改變。
We should extract this responsibility into another class, such as an OrderRepository
:
咱們必須將這個職責抽離出來放到另外的類裏面,好比放到OrderRepository
:
<!-- lang:php --> 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() )); } }
Then, we can inject our repository into the OrderProcessor
, alleviating it of the responsibility of researching an account's order history:
而後咱們能夠將咱們的資料庫(譯者注:OrderRepository )注入到OrderProcessor
裏,幫後者承擔起對帳戶訂單歷史的處理責任:
<!-- lang:php --> 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); } }
Now that we have abstracted our order data gathering responsibilities, we no longer have to change our OrderProcessor
when the method of retrieving and logging orders changes. Our class responsibilities are more focused and narrow, providing for cleaner, more expressive code, and a more maintainable application.
如今咱們提取出了收集訂單數據的責任,當讀取和寫入訂單的方式改變時,咱們再也不須要修改OrderProcessor
這個類了。咱們的類的職責更加的專一和精確,這提供了一個更乾淨、更有表現力的代碼,同時也是更容易維護的代碼。
Keep in mind, the Single Responsibility Principle isn't just about less line of code, it's about writing classes that have a narrow responsibility, and a cohesive set of available methods, so make sure that all of the methods in a class are aligned with the overall responsibility of that class. After building a library of small, clear classes with well defined responsibilities, our code will be more decoupled, easier to test, and friendlier to change.
請記住,單一職責原則的關鍵不單單是讓函數變短,而是寫出職責更精確更高內聚的類,因此要確保類裏面全部的方法都屬於該類的職責之下的。在創建一個小巧、清晰且職責明確的類庫之後,咱們的代碼會更加解耦,更容易測試,而且更易於更改。