TypeScript 字段修飾符設計說明
概述
在 LanguageService 類中,不同的字段使用了不同的訪問修飾符,這是基於封裝原則和使用場景的精心設計。
字段分析
1. private static readonly LANGUAGE = 'language'
修飾符說明
private: 私有訪問,只能在此類內部訪問static: 靜態成員,屬於類而非實例readonly: 只讀屬性,初始化後不可修改
設計原因
- 安全性: 作為 localStorage 的鍵名,不應被外部修改
- 共享性: 所有實例使用相同的鍵名,適合靜態
- 不可變性: 鍵名不應在運行時改變
使用場景
// ✅ 正確:在類內部使用
localStorage.setItem(LanguageService.LANGUAGE, 'zh-tw');
// ❌ 錯誤:外部無法訪問
// LanguageService.LANGUAGE // 編譯錯誤
2. language$ = new ReplaySubject<LangChangeEvent>(1)
修飾符說明
- 無修飾符 =
public(TypeScript 默認)
設計原因
- 觀察者模式: 作為 RxJS Subject,需要被外部訂閱
- 實例依賴: 每個服務實例有自己的狀態流
- 框架慣例: Angular 服務通常公開 Observable 供組件消費
使用場景
// ✅ 正確:組件訂閱語言變化
languageService.language$.subscribe(event => {
console.log('Language changed:', event.lang);
});
3. languageList = ['en-us', 'zh-tw', 'zh-cn']
修飾符說明
- 無修飾符 =
public(TypeScript 默認)
設計原因
- 配置數據: 提供支持的語言列表供外部使用
- 實例共享: 所有實例使用相同列表
- 只讀意圖: 雖然沒有
readonly,但實際上不應修改
使用場景
// ✅ 正確:獲取支持的語言
const languages = languageService.languageList;
// ⚠️ 潛在問題:可以被修改(但不推薦)
languageService.languageList.push('ja-jp'); // 不應該這麼做
TypeScript 默認訪問修飾符
類成員默認值
- 字段和方法:
public(如果沒有指定修飾符) - 構造函數參數:
public(如果沒有指定修飾符)
實際效果
class Example {
field1; // 等同於 public field1;
private field2; // 私有
public field3; // 明確公開
}
設計原則
1. 最小權限原則
- 只暴露必要的公共接口
- 內部實現細節保持私有
2. 不可變性
- 常量使用
readonly - 避免意外修改
3. 實例 vs 靜態
- 實例狀態:每個實例獨有
- 靜態常量:類級別共享
建議改進
為 languageList 添加 readonly
readonly languageList = ['en-us', 'zh-tw', 'zh-cn'];
或者使用常量
private static readonly SUPPORTED_LANGUAGES = ['en-us', 'zh-tw', 'zh-cn'];
總結
字段修飾符的選擇基於: - 訪問控制: 誰能訪問這個字段 - 生命周期: 字段是屬於類還是實例 - 可變性: 字段是否應該被修改 - 使用模式: 字段如何被消費
這種設計平衡了封裝性、可用性和維護性。