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'];

總結

字段修飾符的選擇基於: - 訪問控制: 誰能訪問這個字段 - 生命周期: 字段是屬於類還是實例 - 可變性: 字段是否應該被修改 - 使用模式: 字段如何被消費

這種設計平衡了封裝性、可用性和維護性。 d:\wpg\shipment-notice-platform-web\field-modifiers-design.md