前幾天在網上看到一種設計方式,闡述了一種讓代碼看起來跟擴展性高的一種思維方式,作者透過實際例子描述如何從一開始的設計演化到最後的概念,這樣子的設計概念其實充滿在 Laravel 當中,我認為是相當值得學習的一個作法與思維,以下為實際演示和相關我理解的註解:
首先作者提出了一種原有的代碼設計思路,這邊可以看到示例代碼,用來處理相關 throw
和 report
的機制:
class Flaky
{
protected $throw = true;
public function reportFailures()
{
$this->throw = false;
}
public function throwFailures()
{
$this->throw = true;
}
protected function handle(Exception $e)
{
$this->throw ? throw $e : report($e);
}
}
這邊是一個很基礎的設計,可以看到透過呼叫 method 來改變 throw property 來改變最後 handle 的動作。然而當有新的方法,例如 logFailures
,就必須調整兩個部分:
- 新增
logFailures
方法 - 調整 handle 邏輯
這樣會導致會大幅度去調整原有邏輯跟方法,而沒有一個通用的方法,而且新增的邏輯是有機會跟原本方法不一樣,因此作者透過步驟去分析跟設計,而這樣子的作法也是 Laravel 代碼庫中的實踐方法:
class Flaky
{
protected $handleFailure;
public function __construct()
{
$this->throwFailures();
}
public function handleFailures($callback)
{
// 這邊透過 callback 的行為來增加代碼彈性,使其作用域在內部
$this->handleFailure = $callback;
}
public function reportFailures()
{
$this->handleFailures(function($e) {
report($e);
});
}
public function throwFailures()
{
$this->handleFailures(function($e) {
throw $e;
});
}
// new method
public function logFailures()
{
$this->handleFailures(function($e) {
logger($e)
});
}
protected function handle(Exception $e)
{
call_user_func($this->handleFailure, $e);
}
}
透過 handle
去 call handleFailure
,除了內部提供的 reportFailures
, throwFailures
, logFailures
,也可以直接呼叫 handleFailure
進行自定義方法:
$hanlder = (new Flaky)->handleFailure(function($e) {
logger($e);
throw ResponseException("Something went wrong");
})
讓代碼去保持一定可開放性也可以針對需求做出基礎的方法,可以作為一種設計思路。
I'm always on the lookout for a good "make more things the same" refactor and I just found one!
— Aaron Francis (@aarondfrancis) March 8, 2023
Make your life easy, make more things the same. pic.twitter.com/tQfnqSZ84u