產能模組 (Capacity Module) OOA
來源:fp(已簽核 2026-06-15) 上游消費(domain-model OOA,不重定義):
Resource/WorkCapability/ResourcePool/AvailableCapacity/CapacitySlot/Occupation(§DM-OA-4/8/9/10/11/12)、OperationCoordinate/DataBox生產端(對外契約):resource-selection consumed portResourceCouplingQuery.allowedTargets(§RS-OA-5)+eligible/WorkCapability配對 下游:pseudo(尚未建立) 性質:單一 feature OOA;產能真相源頭,經 ACL 投影餵粗排等下游 狀態:草稿 — Step 1–3 完成(詞彙+類別圖+SOLID);Fork A/B 已拍板;patterns 裁定不新增;進簽核前須跑consistency-audit(動到共用 domain-modelResourcedelta 與AvailableCapacity投影)
1. 領域詞彙(Ubiquitous Language)
沿用既有(consume、不重定義)
| 詞彙 | 英文 | 出處 | 在本模組的角色 |
|---|---|---|---|
| 資源 | Resource | §DM-OA-4 | 產能承載主體;本 OOA 將其 flat → abstract base + 4 子類(capacity 為此 delta 的 owner,見子圖①) |
| 工作能力 | WorkCapability | §DM-OA-8 | Map<ProcessId, Set<WorkCenterId>>;UC-B 配對依據(合一 pair 形狀不變) |
| 資源主檔 | ResourcePool | §DM-OA-9 | eligible(processId, workCenterId) 生產端(UC-B,沿用、不重建) |
| 可用產能/產能格 | AvailableCapacity/CapacitySlot | §DM-OA-10/11 | 資源×日讀模型=ACL 投影目標(只定 port 邊界,不在本模組寫) |
| 工序座標 | OperationCoordinate | §DM-OA-5 | 下游佔用的 occupier(本模組不碰佔用) |
| 製程時間參數 | DataBox | §DM-OA-6 | changeOverTime 供下游推 CO 佔用量(不在本模組算,§CAP-FS-11) |
本模組新建模
型別階層(domain-model §DM-OA-4 delta,capacity 為 owner;不另給新 CAP 碼)
| 詞彙 | 英文 | 說明 |
|---|---|---|
| 資源(抽象) | Resource(abstract) | flat → abstract,加 type() 自報型別、allowedTargets() 多型生產端 |
| 機台/模具/操作員/技師 | Machine/Mold/Operator/Technician | 4 子類,皆第一級資源(§CAP-UR-1/10) |
時間軸子系統(domain-model 從無 → 本 OOA 首建;UC-A/UC-D 核心)
- §CAP-OA-1
- 詞彙:行事曆
- 英文:
Calendar - 說明:日曆天框架;把週期班表展開到日期範圍每一天
- 對應 FS:UC-A 步驟2
- §CAP-OA-2
- 詞彙:班表
- 英文:
RecurringShift - 說明:dayOfWeek+起始時間+
Duration+多組休息;含跨日 - 對應 FS:UC-A 步驟1、§CAP-UR-12/13
- §CAP-OA-3
- 詞彙:加班/休息例外
- 英文:
CalendarException - 說明:日曆天+起始+時長+kind(加班∪/休息−),對班表區間做集合運算
- 對應 FS:UC-A 步驟3、§CAP-FS-2
- §CAP-OA-4
- 詞彙:可用時間區段
- 英文:
TimeSlot - 說明:
[起, 迄)+ 歸屬日欄位(跨日切段皆歸起班日,§CAP-FS-1) - 對應 FS:UC-A 輸出
- §CAP-OA-5
- 詞彙:資源班表(聚合)
- 英文:
ResourceSchedule - 說明:keyed by
ResourceId,聚合三件套(行事曆/班表/加班休息) - 對應 FS:UC-A 步驟1(資源自帶班表)
- §CAP-OA-6
- 詞彙:資源可用時間解析器
- 英文:
ResourceAvailabilityResolver - 說明:UC-A:給 schedule + 日期範圍 →
List<TimeSlot>(已集合運算/扣休息/跨日切段) - 對應 FS:UC-A
- §CAP-OA-7
- 詞彙:可用產能彙整
- 英文:
CapacityAvailabilityView - 說明:UC-D:
{Resource → List<TimeSlot>},raw 可用、不扣佔用(§CAP-FS-10) - 對應 FS:UC-D
對外契約 / port(生產端,給下游消費)
- §CAP-OA-8
- 詞彙:資源班表載入
- 英文:
ResourceScheduleProvider - 說明:port:隱藏班別/班表設定來源(前端設定介面)→ 載入
ResourceSchedule - 對應 FS:UC-A
- §CAP-OA-9
- 詞彙:單向限制關聯查詢
- 英文:
ResourceCouplingQuery - 說明:
allowedTargets(restrictive) → Set<ResourceId>,對齊 resource-selection consumed port§RS-OA-5 - 對應 FS:UC-C
- §CAP-OA-10
- 詞彙:日投影 port
- 英文:
DailyCapacityProjection - 說明:ACL port:資源×時間區段 → 資源×日
AvailableCapacity;只定介面,演算法留 pseudo - 對應 FS:UC-D、§CAP-FS-12
內部 VO 維持本地號、不掛全域碼:
BreakPeriod、ExceptionKind(enum)、ResourceType(enum)。
2. 關係草圖
Resource(abstract) ──type()──> ResourceType
├─ Machine / Mold / Operator / Technician
├─ has 1 ──> WorkCapability 〔eligible 配對依據, §DM-OA-8〕
└─ allowedTargets() 多型 〔Operator→機台集 / Technician→模具集, UC-C〕
ResourceAvailabilityResolver(schedule, 日期範圍) 〔UC-A〕
├─ schedule 經 ResourceScheduleProvider 載入
├─ RecurringShift.materialize ── Calendar 展開到每日
├─ 套 CalendarException (加班 ∪ / 休息 −) → 扣班表自帶休息 (−)
└─ 產 List<TimeSlot>(帶歸屬日;跨日切段皆歸起班日)
CapacityAvailabilityView(pool, 日期範圍) 〔UC-D〕
└─ 對 ResourcePool 每個 Resource 跑 Resolver → {Resource → List<TimeSlot>}
└─(ACL port) DailyCapacityProjection ──> AvailableCapacity/CapacitySlot(資源×日) 〔§CAP-FS-12〕
ResourceCouplingQuery.allowedTargets(restrictive) ──> Set<ResourceId> 〔UC-C, 對齊 §RS-OA-5〕
3. 類別圖
子圖① — Resource 型別階層(domain-model §DM-OA-4 delta,capacity 為 owner)
classDiagram direction TB class Resource { <<abstract>> -id: ResourceId -capability: WorkCapability +canPerform(processId, workCenterId) boolean +type() ResourceType +allowedTargets() Set~ResourceId~ } class Machine class Mold class Operator { -allowedMachines: Set~ResourceId~ } class Technician { -allowedMolds: Set~ResourceId~ } class ResourceType { <<enumeration>> MACHINE MOLD OPERATOR TECHNICIAN } Resource <|-- Machine Resource <|-- Mold Resource <|-- Operator Resource <|-- Technician Resource --> ResourceType : type() note for Resource "§DM-OA-4 flat→abstract(形狀同 resource-selection 子圖 A,本份為權威 owner)。type() 子類自報型別當輸出 bucket;allowedTargets() 為單向限制關聯多型生產端:Machine/Mold 回空集,Operator/Technician 回受限目標集——讓 4 子類賺到存在理由(Fork B)"
地理位置(§CAP-UR-3)/隸屬工作站(§CAP-UR-11)behavior 層不建模:隸屬工作站已摺進
WorkCapability的 pair、地理位置為純資訊欄位不參與任何行為(§CAP-FS-7),沿用 domain-model 對「隸屬工作站」的 YAGNI 處置。
子圖② — 時間軸子系統(本 OOA 首建,UC-A/UC-D 核心)
classDiagram direction TB class ResourceAvailabilityResolver { <<Domain Service>> +resolve(schedule, dateRange) List~TimeSlot~ } class CapacityAvailabilityView { <<Domain Service>> +availability(pool, dateRange) Map~ResourceId, SlotList~ } class ResourceScheduleProvider { <<interface>> +findFor(resourceId) Optional~ResourceSchedule~ } class ResourceSchedule { -resourceId: ResourceId -calendar: Calendar -shifts: List~RecurringShift~ -exceptions: List~CalendarException~ } class Calendar { <<value object>> +daysIn(dateRange) List~LocalDate~ } class RecurringShift { <<value object>> -dayOfWeek: DayOfWeek -startTime: LocalTime -duration: Duration -breaks: List~BreakPeriod~ +isOvernight() boolean +materialize(date) List~TimeSlot~ } class BreakPeriod { <<value object>> -startTime: LocalTime -duration: Duration } class CalendarException { <<value object>> -date: LocalDate -startTime: LocalTime -duration: Duration -kind: ExceptionKind +applyTo(slots) List~TimeSlot~ } class ExceptionKind { <<enumeration>> OVERTIME REST } class TimeSlot { <<value object>> -start: LocalDateTime -end: LocalDateTime -attributionDate: LocalDate } class ResourcePool { +eligible(processId, workCenterId) List~Resource~ } ResourceAvailabilityResolver ..> ResourceScheduleProvider : 載入 schedule ResourceAvailabilityResolver ..> ResourceSchedule : 讀 ResourceAvailabilityResolver ..> TimeSlot : produces CapacityAvailabilityView ..> ResourceAvailabilityResolver : per resource CapacityAvailabilityView ..> ResourcePool : 取資源池 ResourceScheduleProvider ..> ResourceSchedule : findFor ResourceSchedule "1" *-- "1" Calendar ResourceSchedule "1" *-- "*" RecurringShift ResourceSchedule "1" *-- "*" CalendarException RecurringShift "1" *-- "*" BreakPeriod RecurringShift ..> TimeSlot : materialize CalendarException --> ExceptionKind CalendarException ..> TimeSlot : applyTo
SlotList=List<TimeSlot>(避免 Mermaid 巢狀泛型)。集合運算固定順序(§CAP-FS-2,Fork 1a):
RecurringShift.materialize產底 → 逐筆CalendarException.applyTo(OVERTIME ∪、REST −)→ 扣班表自帶BreakPeriod(−)。跨日由materialize在日界切兩段、TimeSlot.attributionDate皆=起班日(§CAP-FS-1,Fork 2a)。重疊衝突依序運算、不擋(模組外 UI alert)。
子圖③ — 對外 port + ACL 投影邊界(只定介面)
classDiagram direction TB class ResourceCouplingQuery { <<interface>> +allowedTargets(restrictive) Set~ResourceId~ } class DailyCapacityProjection { <<interface>> +project(availability) AvailableCapacity } class AvailableCapacity { +slotOf(resourceId, day) CapacitySlot } note for ResourceCouplingQuery "生產端,對齊 resource-selection consumed port §RS-OA-5;本模組實作委派 Resource.allowedTargets() 多型" note for DailyCapacityProjection "ACL port:資源×時間區段 → 資源×日(§DM-OA-10)。只定介面;投影演算法留 pseudo(§CAP-FS-12 / S4)" DailyCapacityProjection ..> CapacityAvailabilityView : 吃彙整輸出 DailyCapacityProjection ..> AvailableCapacity : 產
4. 設計決策
Step 1 已拍板(2026-06-15)
- Fork 1(a) 集合運算統一:
CalendarException帶kind(OVERTIME∪/REST−),Resolver 依 §CAP-FS-2 固定順序套用;不用例外子類(pattern-itis)。 - Fork 2(a) 歸屬日掛
TimeSlot:每段自帶attributionDate,跨日切兩段各帶歸屬日(最貼 FS I/O)。 - Fork 3(a)
eligible沿用ResourcePool:不另建配對服務;本模組職責止於「定義 Resource 帶哪些WorkCapability」,配對查詢沿用§DM-OA-9。 - 型別階層 owner(已拍板):capacity-module 為
§DM-OA-4flat→abstract+4 子類 delta 的 owner,與 resource-selection 子圖 A 對齊同形狀;resource-selection 那份 audit 的未結 ❌(abstract 化致 2 處new Resource(...)無法編譯)交由本 OOA 簽核前那次consistency-audit一併誠實化。 - ACL 投影深度(已拍板):本 OOA 只定
DailyCapacityProjection邊界 + port 介面;投影演算法留 pseudo。
Step 2 已拍板(2026-06-15,Fork A / B)
- Fork A(a) 另立
ResourceSchedule聚合(keyed byResourceId),Resolver 經ResourceScheduleProvider載入。理由:時間軸是 capacity-module 的,不把欄位灌進共用Resource,把 DM delta 鎖在「abstract+子類」最小範圍(對齊 resource-selection 那份待收 ❌「Resource delta 須手術式最小」)。 - Fork B(a)
allowedTargets()多型在子類(Operator→allowedMachines、Technician→allowedMolds、Machine/Mold→{}),ResourceCouplingQuery實作只委派多型。理由:兌現 resource-selection LSP 觀察點「耦合差異行為必須長在子類」,讓 4 子類賺到存在理由、capacity 當 owner 名實相符;耦合資料由 provider 載入填進子類實例(資料來源 vs 行為歸屬分離)。
FS 待裁定收斂(FS §待裁定 Q1~Q3)
- Q1(歸屬日 vs 日投影):
TimeSlot.attributionDate隨投影帶進DailyCapacityProjection;下游粗排「日粒度怎麼吃歸屬日」的細節屬投影演算法(pseudo)與粗排對齊,OOA 只保證歸屬日穿透 port 不遺失。 - Q2(配對特例 vs 節點單一對):
eligible維持 exact pair(§CAP-FS-4),特例(同製程異工作站)不在本層放寬,走下游 resource-selection 指派路徑(§CAP-FS-5)。「節點=工作站-製程單一對」不變量在本層保住。 - Q3(Resource 多型 delta):capacity 為 owner,與 resource-selection 子圖 A 同形狀(abstract + 4 子類 +
type()/allowedTargets());code 衝擊誠實化交簽核前 audit。
5. SOLID 審查 + 設計模式
Step 3 完成(2026-06-15)。四檢點逐一具名判 + pattern 逐一裁定「不新增」。
Part A — SOLID 檢查
| 原則 | 對象 | 結論 |
|---|---|---|
| SRP | ResourceAvailabilityResolver / CapacityAvailabilityView / DailyCapacityProjection | ✅ 三者各一句可述、不含 and:Resolver「解析單一資源的可用時間區段」、View「彙整資源池每個資源的可用區段」、Projection「把資源×時間區段投影成資源×日」。Resolver 內的「展開/集合運算/跨日切段」是同一演算法的步驟、非三職責(呼應 resource-selection ResourceSelector 判法)。ResourceSchedule/RecurringShift/CalendarException 行為長在自己資料上(materialize/applyTo),非貧血模型。 |
| OCP | Resource.allowedTargets() / Resource.type()(多型);CalendarException.kind(資料驅動) | ✅(多型面)allowedTargets()/type() 子類各自實作,新增 restrictive 型別不改既有方法、無 instanceof。⚠️ 觀察點(非現在的問題):Fork 1(a) 以 kind(OVERTIME∪/REST−) 資料驅動取代例外子類;集合運算封閉(聯集/差集兩種),目前安全。若出現第三種非集合語意的例外 kind,applyTo 會長出 switch → 屆時才回頭收 Template Method(即 Fork 1 的 (b))。 |
| LSP | 四子類 Machine/Mold/Operator/Technician | ✅ 無違反,且本 OOA 正面解掉 resource-selection 的 LSP 紅旗:經 Fork B,Operator/Technician 有了真行為(allowedTargets 回各自集合)、Machine/Mold 回 {} 是誠實的有效答覆(它們不限制誰),非 UnsupportedOperationException。四子類就此賺到存在理由。保持誠實的條件:未來型別差異行為仍須長在子類;若只能塞回 service 的 if-else,即階層失格、該回退 flat(DM delta 回退訊號)。 |
| ISP | ResourceScheduleProvider / ResourceCouplingQuery / DailyCapacityProjection | ✅ 三 port 各單一方法(findFor/allowedTargets/project),夠窄、無實作者被迫空實作。沿用的 ResourcePool.eligible 亦單一查詢面。 |
| DIP | 三 port | ✅ domain 定介面、infra/ACL 實作的依賴反轉:ResourceScheduleProvider 藏班表設定來源(前端設定介面)、DailyCapacityProjection 藏資源×日投影、ResourceCouplingQuery 為對齊下游的生產端契約。domain 服務不碰具體儲存/格式。 |
Part B — 設計模式(裁定:不新增)
| # | Pattern | 候選用途 | 裁定 |
|---|---|---|---|
| 1 | Strategy / Template Method | 加班/休息集合運算、例外型別 | ❌ 不採。即 Fork 1 的 (b);僅 ∪/− 兩種、集合運算封閉、非 runtime 抽換,抽象化會打散內聚的解析演算法(§CAP-FS-2 固定順序)。出現非集合語意 kind 時再回來。 |
| 2 | Specification | 能力配對 / 篩選 | ❌ 不採。eligible 為 exact pair 單一謂詞(§CAP-FS-4)、無 and/or/not 組合需求;耦合過濾屬下游 resource-selection。 |
| 3 | Repository | ResourcePool + ResourceScheduleProvider | ✅ 已隱含採用。兩者本質即資源主檔/班表 repository 抽象,標註即可、不新增工。 |
| 4 | Adapter (ACL) | DailyCapacityProjection | ✅ 已隱含採用。port 本身就是資源×時間區段 → 既有資源×日讀模型的防腐轉接(§CAP-FS-12),設計使然、標註即可。 |
健康結論:本設計目前不缺 pattern,硬塞為 pattern-itis(對齊 resource-selection OOA 結論)。
6. functional spec 對照
| FS 項目 | 對應 OOA |
|---|---|
| UC-A 解析資源可用時間區段 | ResourceAvailabilityResolver.resolve + RecurringShift.materialize + CalendarException.applyTo + Calendar.daysIn |
| UC-B 能力-工作站配對 | ResourcePool.eligible(§DM-OA-9)+ WorkCapability.canPerform(§DM-OA-8,exact pair) |
| UC-C 單向限制關聯查詢 | ResourceCouplingQuery.allowedTargets(§CAP-OA-9)+ Resource.allowedTargets() 多型 |
| UC-D 彙整資源×時間區段可用產能 | CapacityAvailabilityView.availability(§CAP-OA-7)+ DailyCapacityProjection(§CAP-OA-10,投影) |
| §CAP-FS-1 跨日歸起班日 | RecurringShift.isOvernight + materialize 日界切兩段;TimeSlot.attributionDate 皆=起班日 |
| §CAP-FS-2 集合運算固定順序 | Resolver 編排:materialize → 逐筆 applyTo(∪/−) → 扣 BreakPeriod(−);重疊衝突不擋(模組外 alert) |
| §CAP-FS-3 無班別日空輸出 | 該日無 RecurringShift match → 空;Resolver 回空清單、不報錯 |
| §CAP-FS-4 eligible exact pair | WorkCapability.canPerform exact(§DM-OA-8) |
| §CAP-FS-5 特例不在本層 | eligible 維持 exact、不放寬工作站;特例走下游指派路徑(本 OOA 不建模) |
§CAP-FS-6 能力空集回 {} | ResourcePool.eligible 回空 List、不拋(fail-fast 屬下游 §RS-FS-5) |
| §CAP-FS-7 地理位置純資訊 | 不建模(§3 子圖①下方 note,YAGNI) |
| §CAP-FS-8 限制單向 | allowedTargets 單向、無反向查詢 |
§CAP-FS-9 未設定/設空回 {} | Operator/Technician.allowedTargets 預設空集;Machine/Mold 恆回 {} |
| §CAP-FS-10 raw 可用、不扣佔用 | CapacityAvailabilityView 只彙整 TimeSlot、不碰 Occupation/FREEZE/IN_RUN |
| §CAP-FS-11 模治具/技師佔用量屬下游 | 四型別皆第一級資源、同走時間軸;DataBox.changeOverTime 佔用量計算不在本模組 |
| §CAP-FS-12 日投影由 ACL | DailyCapacityProjection port(只定介面,演算法留 pseudo) |
簽核
- 編輯者: / 日期:
- Reviewer: / 日期:
- 草稿階段;Step 1–2 完成。進簽核前須:① 確認 Fork A/B;② 完成 Step 3 SOLID + FS 對照;③ 跑
consistency-audit(動到共用 domain-modelResourcedelta 與AvailableCapacity投影關係,且與 resource-selection 子圖 A/其未結 ❌ 交織)。