單一職責原則 (Single Responsibility Principle, SRP):
一個類別應該**只有一個引起它變更的原因**,即**只做一件事**。
— Robert C. Martin (Uncle Bob)
SRP 是 SOLID 五大原則之首,是**低耦合、高內聚**在類別層級的具體體現。職責過多會導致:修改一處牽一髮動全身、測試困難、團隊協作衝突。

// 問題:IUser 同時包含資料屬性 (BO) 與業務行為 (Biz)
// 任何屬性變更或行為變更都會影響實作類別
public interface IUser
{
string Name { get; set; }
int Age { get; set; }
void Add();
void Update();
void Delete();
}

// 資料傳輸介面 (BO - Business Object)
public interface IUserBO
{
string Name { get; set; }
int Age { get; set; }
}
// 業務行為介面
public interface IUserBiz
{
void Add(IUserBO user);
void Update(IUserBO user);
void Delete(string userId);
}
// 實作類別可同時實作兩介面,視使用情境注入不同介面
public class UserInfo : IUserBO, IUserBiz { /* ... */ }
// 使用端:依介面程式設計
public class UserService
{
private readonly IUserBiz _biz;
public UserService(IUserBiz biz) => _biz = biz;
public void Register(IUserBO user) => _biz.Add(user);
}
效益:資料結構變更 (如新增 Email) 僅影響 `IUserBO` 實作;業務流程變更 (如加入驗證) 僅影響 `IUserBiz` 實作,兩者**獨立演進**。

public class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
public void Draw(Graphics g) { /* 繪圖邏輯,依賴 UI 庫 */ }
public int Area() => Width * Height; // 純計算,無 UI 相依
}
問題:

// 幾何計算 - 穩定、無外部相依
public class RectangleGeometry
{
public int Width { get; set; }
public int Height { get; set; }
public int Area() => Width * Height;
}
// 繪圖渲染 - 易變、依賴 UI
public class RectangleRenderer
{
public void Draw(Graphics g, RectangleGeometry geom) { /* ... */ }
}
public interface IPhone
{
void Dial(string number); // 協議管理:建立連線
void HangUp(); // 協議管理:斷開連線
void Chat(object data); // 資料傳輸:通話內容
void Answer(object data); // 資料傳輸:接收內容
}
兩大職責:通訊協議管理 (Dial/HangUp) 與 資料傳輸 (Chat/Answer)。協議變更 (如 5G) 與資料格式變更 (如加密) 獨立演進。

public interface IProtocol { void Dial(string n); void HangUp(); }
public interface IDataTransfer { void Chat(object d); void Answer(object d); }
// 組合關係:Phone 包含 IProtocol 與 IDataTransfer 實例
public class Phone
{
public IProtocol Protocol { get; set; }
public IDataTransfer Transfer { get; set; }
}
// 缺點:組合為強耦合,生命週期綁定,擴充性受限

public class SmartPhone : IProtocol, IDataTransfer
{
public void Dial(string n) { /* 5G/4G 邏輯 */ }
public void HangUp() { /* ... */ }
public void Chat(object d) { /* 加密傳輸 */ }
public void Answer(object d) { /* 解密接收 */ }
}
// 使用端:依介面注入,互不干擾
public class CallManager
{
private readonly IProtocol _protocol;
public CallManager(IProtocol protocol) => _protocol = protocol;
public void StartCall(string num) => _protocol.Dial(num);
}
優勢:
| 檢核點 | 違反徵兆 | 重構手法 |
|---|---|---|
| 類別行數 > 200 | 方法過多、邏輯雜糅 | Extract Class / Extract Interface |
| 引用命名空間 > 5 | 跨層相依 (UI、DB、Network 混雜) | 分層架構、依賴倒置 |
| 修改原因 > 1 | 改 UI 牽動 DB、改演算法牽動介面 | 拆分類別、Facade/Proxy 模式 |
| 單元測試需大量 Mock | 相依過多外部服務 | 介面隔離、注入 Mock |
SRP 不是「類別越小越好」,而是**依業務變更軸線劃分邊界**。識別「什麼會一起變、什麼會分開變」是架構師的核心能力。實務中結合 **ISP (介面隔離)**、**DIP (依賴倒置)**、 **Facade/Proxy/Strategy** 等模式,才能落地「高內聚、低耦合」的系統架構。