新规hook
This commit is contained in:
@@ -9,8 +9,7 @@
|
||||
|
||||
### 1.1 单一权威数据源(Single Source of Truth)
|
||||
|
||||
同一业务数据**只能有一个计算/写入的地方**,其余模块只读取、不重算。多处并行计算同一结果,必随
|
||||
规则演化而分叉、互相矛盾。
|
||||
同一业务数据**只能有一个计算/写入的地方**,其余模块只读取、不重算;多处并行计算必随规则演化而分叉、矛盾。
|
||||
|
||||
- 上游**算 + 写 + 校验**,下游**只读 + 消费**。
|
||||
- 需要某数据时,**读权威源**,而不是"顺手再算一遍"。
|
||||
@@ -43,18 +42,14 @@
|
||||
| 编排 vs 算法 | 流程编排(controller) | 纯计算(领域算法) |
|
||||
| 输入 vs 逻辑 | 收发包/参数校验 | 业务处理 |
|
||||
|
||||
> 例(决策 vs 机制):自动操作模块只决定"打哪张/是否碰杠胡过",**不实现**胡牌检测/听牌分析;
|
||||
> 后者是领域算法,决策层只**读取其结果**。这既是关注点分离,也是职责边界。
|
||||
> 例(决策 vs 机制):自动操作模块只决定"打哪张/是否碰杠胡过",**不实现**胡牌检测/听牌分析;后者是领域算法,决策层只**读取其结果**。既是关注点分离,也是职责边界。
|
||||
|
||||
### 1.5 对扩展开放、对修改封闭(OCP)
|
||||
|
||||
新增一种玩法/规则/策略/牌型,应当是**新增一段代码并注册**,而**不是**去改动已经稳定、已被测试
|
||||
覆盖的核心流程。
|
||||
新增一种玩法/规则/策略/牌型,应当是**新增一段代码并注册**,而**不是**去改动已经稳定、已被测试覆盖的核心流程。
|
||||
|
||||
- 手段:**注册表 + 策略**、**管线/中间件**、**工厂**(见 [02 篇](./02-可扩展性与配置化.md))。
|
||||
- 收益:核心不动 → 回归风险小;扩展点清晰 → 新人能照葫芦画瓢。
|
||||
- 例:分级决策框架——核心是"取上下文 → 跑管线 → 选结果",新增高级策略只是**写策略对象 +
|
||||
注册 + 单测**三步,核心零改动。
|
||||
- 例:分级决策框架核心是"取上下文 → 跑管线 → 选结果",新增高级策略只是**写策略对象 + 注册 + 单测**三步,核心零改动。
|
||||
|
||||
### 1.6 配置优先于硬编码
|
||||
|
||||
@@ -69,7 +64,7 @@
|
||||
关键路径上数据缺失,**优先报错或返回 `null`**,把问题暴露在**离根因最近**的地方;不要用
|
||||
`|| 0`、`|| []`、`|| ''`、双源回退把缺失悄悄填平。
|
||||
|
||||
- 兜底会把 bug 藏进"看似正常"的流程里,等到很远的下游才爆发,极难定位。
|
||||
- 兜底会把 bug 藏进"看似正常"的流程里,到很远的下游才爆发,极难定位。
|
||||
- 只有**展示层、纯 UI 兼容、非关键日志**字段,才可在明确边界内用安全默认值。
|
||||
- 详见 [03 篇](./03-数据权威·错误处理·演进.md)。
|
||||
|
||||
@@ -77,7 +72,7 @@
|
||||
|
||||
## 2. 前后端参考分层
|
||||
|
||||
下面是一套**成熟、可直接照搬思路**的分层。层次是稳定的,层内文件如何组织由子游戏自定。
|
||||
下面是一套可直接照搬思路的分层。层次是稳定的,层内文件如何组织由子游戏自定。
|
||||
|
||||
### 2.1 后端分层(自上而下依赖)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# 02 · 可扩展性与配置化
|
||||
|
||||
本篇把总则里的 **OCP(对扩展开放)** 和 **配置优先** 落成可直接套用的模式与判据,
|
||||
并给出**避免过度设计**的红线——扩展性是为了"改得动",不是为了炫技。
|
||||
本篇把总则的 **OCP(对扩展开放)** 和 **配置优先** 落成可套用的模式与判据,并给出**避免过度设计**的红线——扩展性是为了"改得动",不是炫技。
|
||||
|
||||
---
|
||||
|
||||
@@ -11,30 +10,25 @@
|
||||
|
||||
### 1.1 注册表 + 策略(Registry + Strategy)— 最常用
|
||||
|
||||
把"一族可替换的行为"抽象成**策略对象**,用**注册表**收集,运行时按上下文选一个执行。
|
||||
新增行为 = 写一个策略 + 注册,**核心零改动**。
|
||||
把"一族可替换的行为"抽象成**策略对象**,用**注册表**收集,运行时按上下文选一个执行。新增行为 = 写一个策略 + 注册,**核心零改动**。
|
||||
|
||||
```
|
||||
Registry(注册表) ── register(strategy) ──▶ [strategyA, strategyB, ...]
|
||||
│
|
||||
Context(只读上下文)──▶ 选择器 select(ctx) ─────────┘──▶ 命中的策略.execute(ctx)
|
||||
Registry ──register(strategy)──▶ [strategyA, strategyB, ...] ──select(ctx)──▶ 命中策略.execute(ctx)
|
||||
```
|
||||
|
||||
- **适用**:AI 决策分级、规则变体、牌型识别族、结算规则族——"同一类事有多种做法"。
|
||||
- **要点**:
|
||||
- 策略只依赖**只读上下文**,不反向修改全局;上下文封装它需要的权威数据。
|
||||
- 有**默认策略兜底**(保证任何输入都有结果),高级策略**按需叠加**。
|
||||
- 策略只依赖**只读上下文**(封装其所需权威数据),不反向修改全局。
|
||||
- 有**默认策略兜底**(任何输入都有结果),高级策略**按需叠加**。
|
||||
- 策略之间**互不知道**对方,新增不影响既有。
|
||||
- **例**:分级决策框架——`Context/Registry/Pipeline + 基础策略 + 占位高级策略`,默认走最低级,
|
||||
高级留扩展点;新增高级策略三步(写策略对象 + register + 单测)零侵入。
|
||||
- **例**:分级决策框架默认走最低级、高级留扩展点;新增高级策略三步(写策略对象 + register + 单测)零侵入。
|
||||
|
||||
### 1.2 管线 / 中间件(Pipeline)
|
||||
|
||||
把一个复杂处理拆成**有序的小步骤**,每步只做一件事、可独立增删。
|
||||
|
||||
```
|
||||
输入 ──▶ [校验] ──▶ [规则A] ──▶ [规则B] ──▶ [收敛] ──▶ 输出
|
||||
每一节点单一职责,可插拔、可测试
|
||||
输入 ──▶ [校验] ──▶ [规则A] ──▶ [规则B] ──▶ [收敛] ──▶ 输出(每节点单一职责、可插拔、可测试)
|
||||
```
|
||||
|
||||
- **适用**:决策流水线、校验链、结算的多阶段计分(比精 → 冲关 → 霸王 → 零和)。
|
||||
@@ -42,7 +36,7 @@ Context(只读上下文)──▶ 选择器 select(ctx) ──────
|
||||
|
||||
### 1.3 工厂(Factory)
|
||||
|
||||
把"根据类型创建/选择实现"的分支收敛到一处,调用方只要"我要一个 X",不关心怎么造。
|
||||
把"根据类型创建/选择实现"的分支收敛到一处,调用方只说"我要一个 X",不关心怎么造。
|
||||
|
||||
- **适用**:胡牌检测按牌型分派、可用操作枚举、不同房型的配置构建。
|
||||
- **要点**:工厂是**唯一**的创建入口,避免 `if(type==...)` 散落各处(那是并行逻辑的温床)。
|
||||
@@ -54,14 +48,13 @@ Context(只读上下文)──▶ 选择器 select(ctx) ──────
|
||||
|
||||
- **适用**:一次数据变化要驱动多个互不相关的表现(动画 + 音效 + 计分板)。
|
||||
- **克制**:
|
||||
- **不要**用事件做"隐式流程控制"——关键流程的因果应显式可追踪,别埋进一堆事件里。
|
||||
- **不要**用事件做"隐式流程控制"——关键流程的因果应显式可追踪。
|
||||
- 事件是**通知**,不是**命令**;订阅方不该反向决定发布方的流程。
|
||||
- 能直接函数调用讲清的因果,就别为"解耦"硬拆成事件。
|
||||
|
||||
### 1.5 统一访问层(Facade over data)
|
||||
|
||||
对"读权威数据"提供一个**统一入口**(如 DataAccessHelper 之类),下游都走它读,不各自摸索
|
||||
数据结构。好处:数据结构演化时只改访问层一处;配合"缺失显式失败",把校验集中。
|
||||
对"读权威数据"提供一个**统一入口**(如 DataAccessHelper),下游都走它读,不各自摸索数据结构。好处:数据结构演化时只改访问层一处;配合"缺失显式失败",把校验集中。
|
||||
|
||||
---
|
||||
|
||||
@@ -89,23 +82,19 @@ Context(只读上下文)──▶ 选择器 select(ctx) ──────
|
||||
|
||||
### 2.3 规则驱动:把玩法开关变成数据
|
||||
|
||||
复杂玩法的差异(人数/局数/扣卡方式/各种开关)应编码成**一份配置**,在入口处**解析一次**,
|
||||
之后全流程**只读消费**:
|
||||
复杂玩法的差异(人数/局数/扣卡方式/各种开关)应编码成**一份配置**,在入口处**解析一次**,之后全流程**只读消费**:
|
||||
|
||||
```
|
||||
房型/配置编码 ──(解析器,解析一次)──▶ 规则对象(结构化、只读)
|
||||
│
|
||||
各模块按需读取规则对象的字段,不再各自解析原始编码、不再散落 if
|
||||
房型/配置编码 ──(解析器,解析一次)──▶ 规则对象(结构化、只读)──▶ 各模块按需读字段,不再各自解析、不再散落 if
|
||||
```
|
||||
|
||||
- **解析只此一处**:避免"多处各自解析同一编码"产生的不一致(这是 SSOT 在配置上的体现)。
|
||||
- **解析只此一处**:避免"多处各自解析同一编码"产生的不一致(SSOT 在配置上的体现)。
|
||||
- **规则对象只读**:下游不回写、不推断缺省;缺字段是**配置或解析的 bug**,应显式暴露。
|
||||
- **新增一个玩法开关** = 编码加一位 + 解析器认它 + 消费点读它,**不改无关逻辑**。
|
||||
|
||||
### 2.4 配置注入优于全局魔法值
|
||||
|
||||
模块需要的配置**从入口传入 / 从权威配置对象读取**,而不是在模块内部埋一堆魔法值或直接摸全局。
|
||||
这让模块**可测试**(注入不同配置跑用例)、**可复用**(换配置即换行为)。
|
||||
模块需要的配置**从入口传入 / 从权威配置对象读取**,而不是在模块内部埋魔法值或直接摸全局。这让模块**可测试**(注入不同配置跑用例)、**可复用**(换配置即换行为)。
|
||||
|
||||
---
|
||||
|
||||
@@ -115,8 +104,8 @@ Context(只读上下文)──▶ 选择器 select(ctx) ──────
|
||||
|
||||
### 3.1 什么时候**不要**加抽象
|
||||
|
||||
- **只有一种实现、且看不到第二种的现实需求** → 不要为"将来也许"预留策略/工厂。先写直接实现。
|
||||
- **YAGNI**:没有当前需求的扩展点就是负债;等第二个变体真的出现,再**重构**成模式(那时你更懂共性)。
|
||||
- **只有一种实现、且看不到第二种的现实需求** → 不要为"将来也许"预留策略/工厂,先写直接实现。
|
||||
- **YAGNI**:没有当前需求的扩展点就是负债;等第二个变体真的出现,再**重构**成模式(那时更懂共性)。
|
||||
- **一次性逻辑** → 不要包装成"通用框架"。通用性从**重复中提炼**,不是凭空设计。
|
||||
|
||||
### 3.2 判断"值不值得抽象"
|
||||
@@ -131,8 +120,7 @@ Context(只读上下文)──▶ 选择器 select(ctx) ──────
|
||||
### 3.3 成熟的判据:三次法则 + 就近演进
|
||||
|
||||
- **三次法则**:同样的东西第 3 次出现时再抽象;第 1、2 次容忍重复。
|
||||
- **就近演进**:先把直接实现写对、写清;当扩展点**自然浮现**(真来了第二个变体),
|
||||
再**收敛**成注册表/策略——此时抽象是"被现实拉出来的",最贴合,也最不会过度。
|
||||
- **就近演进**:先把直接实现写对、写清;当扩展点**自然浮现**(真来了第二个变体),再**收敛**成注册表/策略——此时抽象是"被现实拉出来的",最贴合,也最不会过度。
|
||||
|
||||
> 一句话:**扩展性是留给"已知会变"的地方的;对"稳定不变"的地方,简单直接才是最好的设计。**
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# 03 · 数据权威 · 错误处理 · 演进
|
||||
|
||||
本篇是**正确性**的地基:数据从哪来、错了怎么暴露、代码怎么随规则长大而不腐化。
|
||||
数据权威部分在 `.github/copilot/skills/data-authority-principle.md` 基础上,扩展到**前后端全景**。
|
||||
本篇是**正确性**的地基:数据从哪来、错了怎么暴露、代码怎么随规则长大而不腐化;数据权威部分在既有「数据权威原则」上扩展到**前后端全景**。
|
||||
|
||||
---
|
||||
|
||||
@@ -75,7 +74,7 @@
|
||||
|
||||
## 3. 演进与重构纪律
|
||||
|
||||
代码会随规则长大。让它**长而不腐**的关键,是持续把"并行/重复/临时"收敛掉。
|
||||
代码随规则长大;让它**长而不腐**的关键,是持续把"并行/重复/临时"收敛掉。
|
||||
|
||||
### 3.1 收敛并行实现
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
| 文档 | 定位 |
|
||||
|------|------|
|
||||
| 各端 `development-guide/` | 平台接入 + 工程红线(**能跑、合规**) |
|
||||
| `docs/architecture/` | **本系统**的具体架构说明(是什么样) |
|
||||
| `.github/copilot/skills/data-authority-principle.md` | 数据权威原则(本套 03 篇在其上扩展到前后端) |
|
||||
| **本套 `docs/games/engineering/`** | **平台无关的通用工程与架构规范**(该怎么设计) |
|
||||
| **本套 `engineering/`** | **平台无关的通用工程与架构规范**(该怎么设计) |
|
||||
|
||||
> 具体命名(模块名/文件名/方法名)在本套文档里多为**示例、可自定**;约束的是**做法与结构**,不是具体名字。
|
||||
|
||||
Reference in New Issue
Block a user