純虛構 介紹篇| Pure Fabrication
同病相憐...圖片來源
情境
有一天,設計一套線上學習平台的你,發現 User 類別越長越胖。不只要記錄使用者名稱、帳號、訂閱狀態,還要能註冊、登入、上傳作業、發送 email 驗證信,甚至還負責把作業存進資料庫。
你看著那 400 行的 class,只覺得:這真的像一個使用者會做的事嗎?
同時你也開始擔心——哪天換了 SMTP server 或換了資料庫,整個 User 類別又要大修了。
在物件導向設計裡,常會遇到這些問題:
- 邏輯難以重複使用
- 依賴外部變化的元件(像是資料庫)侵入核心邏輯
- 類別臃腫,做太多事
GRASP 原則提供了一個概念,純虛構。
多態
“ 這種類別是憑空虛構的。理想情況下,分配給這種虛構物的職責要支持高內聚與低耦合,使得這種虛構物清晰或純粹 - 因此稱為純虛構 ”
純虛構(Pure Fabrication)是 GRASP(General Responsibility Assignment Software Patterns)裡的一個設計原則。它主張:
“ 當你找不到合適的領域物件可以負責某件事時,不妨虛構一個專門處理這件事的物件。 ”
這個物件本身不是領域概念(它不是老師、學生、訂單或報名表),但它有一個很明確的任務,常見如:
- 存取資料庫的 Repository
- 發送 email 的 Mailer
- 負責加密的 Encryptor
- 管理排程的 Scheduler
這些物件的目的不是反映真實世界,而是讓程式碼更有結構、更好維護。
舉個例子
純虛構其實已經被廣泛應用在開發的各個角落,像各種工具類,看看下面的舉例就知道了。
發信的例子
你希望使用者註冊帳號時能收到驗證信。你第一版寫的:
csharp
public class User
{
public string Email { get; set; }
public void SendVerificationEmail()
{
// 簡化了設定
var smtp = new SmtpClient("smtp.mailtrap.io");
smtp.Send("noreply@example.com", Email, "請點擊驗證信", "這是一封驗證信。");
}
}
但如果信件要能支援寄出表格,那勢必要修改 User 類別,因此可以把第一版改成
csharp
public class EmailSender
{
public void Send(string to, string content)
{
var smtp = new SmtpClient("smtp.mailtrap.io");
smtp.Send("noreply@example.com", to, "驗證信", content);
}
}
並在 User 進行調用,這樣 User 只要負責調用,不用管理寄信的具體設定
csharp
public class User
{
private readonly EmailSender _emailSender;
public User(EmailSender emailSender)
{
_emailSender = emailSender;
}
public void SendVerificationEmail(string to, string content)
{
_emailSender.Send(to, "請點擊驗證信");
}
}
作者心得
歷經了一年沒發,甚是懷念。