Files
ImmortalSect/doc/弟子管理.md
T

86 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 弟子管理模块设计
模块位置:P1 核心循环(见 `doc/Roadmap.md`)。本文档描述弟子数据模型与弟子管理器的设计。
## 1. 结构:数据类 + 管理器
弟子模块拆分为两层:
| 层 | 文件 | 类型 | 职责 |
| --- | --- | --- | --- |
| 弟子数据类 | `src/Data/Models/Disciple.gd` | RefCounted | 持有弟子的所有信息,纯数据,无逻辑 |
| 弟子管理器 | `src/Character/DiscipleManager.gd` | Node | 添加、删除、查询、修改弟子属性 + 领域操作(修炼结算) |
## 2. 设计模式
| 角色 | 模式 | 说明 |
| --- | --- | --- |
| 弟子数据类 | 纯数据模型 | RefCounted,运行时可变数据,不依赖场景树,可脱离场景单测 |
| 弟子管理器 | 仓储模式(Repository) | CRUD + 查询的集中入口,是弟子数据的唯一管理者 |
| 变化通知 | 观察者模式(Observer) | 管理器发信号,UI/其他系统订阅实时刷新 |
| 弟子创建 | 工厂方法(Factory) | 初始弟子/收徒的创建逻辑收在管理器内 |
**明确不用的方案**
- 不用 ECS:弟子属性固定(境界/技艺/忠诚…),无动态组件需求,是过度设计。
- 不用 Resource/.tres:弟子是运行时可变数据,RefCounted 类最轻量,不走序列化资源。
- 不把所有逻辑塞进数据类:领域操作归管理器,保证修改只有单一入口,信号好通知,测试好做。
## 3. Disciple 数据类(RefCounted,纯数据)
```gdscript
var name: String
var is_mortal: bool # 凡人弟子
var realm_level: int = 1 # 境界 1-9
var cultivation_skill: int = 1 # 种植技艺 1-10
var alchemy_skill: int = 1 # 炼丹技艺 1-10
var loyalty: int = 50 # 忠诚 0-100P1 仅存字段)
var cultivation_exp: int = 0 # 修为进度
```
只读派生(不存储,由属性计算):
- `monthly_cost() -> int`:每月修炼灵石消耗(凡人弟子为 0
- `realm_name() -> String`:境界显示名(凡人 / 炼气X层…)
- `exp_to_next() -> int`:升到下一境界所需修为
## 4. DiscipleManager 管理器(Node,仓储)
```gdscript
signal disciple_added(disciple)
signal disciple_removed(disciple)
signal disciple_attr_changed(disciple, attr_name, old_value, new_value)
func add_disciple(d) -> void
func remove_disciple(d) -> void
func get_disciple(id) -> Disciple
func get_all() -> Array[Disciple]
func get_by_realm(level) -> Array[Disciple]
func count_mortals() -> int
func set_attr(d, attr, value) -> void # 修改唯一入口,内部发信号
func settle_month() -> void # 修炼结算(领域操作)
func to_dict() -> Dictionary # 存档网关
func load_from_dict(d) -> void
```
## 5. 关键设计决策
1. **修改只走管理器**——`set_attr()` 是唯一变更入口,内部统一发 `disciple_attr_changed`。UI 订阅它实时刷新,也为以后忠诚度/事件系统留监听点。
2. **查询返回引用**——性能好(P1 规模无碍),但禁止外部直接写属性;要写必须走管理器。
3. **管理器是 Node,数据类是 RefCounted**——管理器可挂 MainGame/测试场景;数据类脱离场景树也能单测。
4. **领域操作在管理器**——`settle_month()`(修炼消耗灵石、增加修为、境界提升)归管理器,数据类不碰业务逻辑。
5. **存档网关(Unit of Work**——序列化/恢复只经过管理器 `to_dict()/load_from_dict()`,为 SaveSystem 注册预留。
## 6. 测试方式
独立测试场景 `src/Character/test_disciple.tscn`
1. 实例化 DiscipleManager(不依赖其他模块)
2. `_ready()` 中自动执行用例:
- 添加/删除弟子 → 信号是否正确发出
- 查询(get_by_realm / count_mortals
- `set_attr` → 信号带旧值/新值
- `settle_month` → 境界提升/灵石消耗正确
- `to_dict / load_from_dict` 往返一致
3. `print` 输出 PASS/FAIL,编辑器直接运行场景验证