新规hook
This commit is contained in:
@@ -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 次容忍重复。
|
||||
- **就近演进**:先把直接实现写对、写清;当扩展点**自然浮现**(真来了第二个变体),
|
||||
再**收敛**成注册表/策略——此时抽象是"被现实拉出来的",最贴合,也最不会过度。
|
||||
- **就近演进**:先把直接实现写对、写清;当扩展点**自然浮现**(真来了第二个变体),再**收敛**成注册表/策略——此时抽象是"被现实拉出来的",最贴合,也最不会过度。
|
||||
|
||||
> 一句话:**扩展性是留给"已知会变"的地方的;对"稳定不变"的地方,简单直接才是最好的设计。**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user