9.1 KiB
9.1 KiB
01 · 架构总则与分层
本篇给出七大架构总则,并落到一套前后端参考分层上。总则是"为什么这么设计",分层是"具体长什么样"。 所有分层里的模块名均为示例、可自定,约束的是层与依赖方向,不是名字。
1. 七大架构总则
1.1 单一权威数据源(Single Source of Truth)
同一业务数据只能有一个计算/写入的地方,其余模块只读取、不重算。多处并行计算同一结果,必随 规则演化而分叉、互相矛盾。
- 上游算 + 写 + 校验,下游只读 + 消费。
- 需要某数据时,读权威源,而不是"顺手再算一遍"。
- 详见 03 篇 · 数据权威。
1.2 单向依赖,禁止环
分层之间自上而下单向依赖:入口依赖编排、编排依赖领域、领域依赖数据/共享;反向不依赖。
- 稳定依赖原则:越被依赖的层越应稳定(领域/共享层最稳定,入口层最易变)。
- 禁止环形依赖:A 依赖 B、B 又依赖 A,是"职责没分清"的信号,应抽出共同依赖或调整边界。
- 双运行时下尤其致命:环依赖 + 中途
require会在浏览器端崩溃(见 development-guide 的 require 守卫)。
1.3 职责单一、边界清晰
一个职能只在一个模块实现,别的模块需要它就调用,不"图方便"复制一份近似逻辑。
- 判据:写代码前先问"这段逻辑属于谁的职责"。属于别人的,就调用它。
- 权威能力不满足时,在权威模块内扩展,不要在调用方旁路重写。
- 反例:在 A 模块内联 B 模块核心算法的"简化版";同一职能两处并行演化。
1.4 关注点分离(Separation of Concerns)
把"不同变化原因"的代码分开,让每块只因一个原因而改:
| 分离维度 | 一侧 | 另一侧 |
|---|---|---|
| 决策 vs 机制 | "选哪个"(策略/决策) | "怎么做"(算法/规则/执行) |
| 数据 vs 表现 | 状态模型(真相) | 渲染/UI(从数据重建) |
| 编排 vs 算法 | 流程编排(controller) | 纯计算(领域算法) |
| 输入 vs 逻辑 | 收发包/参数校验 | 业务处理 |
例(决策 vs 机制):自动操作模块只决定"打哪张/是否碰杠胡过",不实现胡牌检测/听牌分析; 后者是领域算法,决策层只读取其结果。这既是关注点分离,也是职责边界。
1.5 对扩展开放、对修改封闭(OCP)
新增一种玩法/规则/策略/牌型,应当是新增一段代码并注册,而不是去改动已经稳定、已被测试 覆盖的核心流程。
- 手段:注册表 + 策略、管线/中间件、工厂(见 02 篇)。
- 收益:核心不动 → 回归风险小;扩展点清晰 → 新人能照葫芦画瓢。
- 例:分级决策框架——核心是"取上下文 → 跑管线 → 选结果",新增高级策略只是写策略对象 + 注册 + 单测三步,核心零改动。
1.6 配置优先于硬编码
会变的、复用的、无语义的值不写死在逻辑里,外提为常量/配置,用数据驱动行为。
- 分数、阈值、类型字符串、跨模块 key → 常量;成套玩法开关 → 配置对象/规则编码。
- 让"改规则"变成"改配置",而不是"改代码 + 重测逻辑"。
- 详见 02 篇 · 配置化与去硬编码。
1.7 显式失败优于隐式兜底
关键路径上数据缺失,优先报错或返回 null,把问题暴露在离根因最近的地方;不要用
|| 0、|| []、|| ''、双源回退把缺失悄悄填平。
- 兜底会把 bug 藏进"看似正常"的流程里,等到很远的下游才爆发,极难定位。
- 只有展示层、纯 UI 兼容、非关键日志字段,才可在明确边界内用安全默认值。
- 详见 03 篇。
2. 前后端参考分层
下面是一套成熟、可直接照搬思路的分层。层次是稳定的,层内文件如何组织由子游戏自定。
2.1 后端分层(自上而下依赖)
┌─────────────────────────────────────────────┐
│ 入口层 Entry 收包薄委托:一操作一入口,只接住并转交 │ 易变
├─────────────────────────────────────────────┤
│ 收发层 IO 参数校验、响应构建、序列化、差异化广播 │
├─────────────────────────────────────────────┤
│ 编排层 Orchestrate 流程编排、状态机推进、跨模块协调(不含算法) │
├─────────────────────────────────────────────┤
│ 领域层 Domain 规则/算法权威实现(胡牌/听牌/计分/牌型…) │
├─────────────────────────────────────────────┤
│ 数据层 Data 对局状态、状态管理、统一访问层 │
├─────────────────────────────────────────────┤
│ 共享层 Shared 前后端逐字相同的纯逻辑与常量 │ 最稳定
└─────────────────────────────────────────────┘
依赖方向:上层 → 下层(下层绝不反向依赖上层)
- 入口层薄:只做"接住请求 → 委托",不写业务;一操作一入口,不做二次路由。
- 领域层是权威:所有"能不能胡/听什么/怎么算分"的算法只此一份,别层调用。
- 数据层是唯一状态落点:对局状态集中管理,读写走统一访问层,避免散落。
- 共享层最底、最稳定:见 [03 篇 · 数据权威] 与各端 development-guide 的 shared 说明。
2.2 前端分层(自上而下依赖)
┌─────────────────────────────────────────────┐
│ 入口层 Entry 平台受限入口:只解包转交,不写业务 │ 易变
├─────────────────────────────────────────────┤
│ 分发层 Dispatch 唯一收包口,按 rpc 路由到处理器(纯路由表) │
├─────────────────────────────────────────────┤
│ 处理层 Controllers 一类消息一处理器:改数据模型 / 触发表现 │
├─────────────────────────────────────────────┤
│ 状态层 Model 前端状态真相(界面从它无歧义重建) │
├─────────────────────────────────────────────┤
│ 表现层 View/Managers 渲染、动画、音频、资源(从状态派生) │
├─────────────────────────────────────────────┤
│ 共享层 Shared 与服务端同源的纯逻辑(只读同步副本) │ 最稳定
└─────────────────────────────────────────────┘
表现从状态派生:任何时刻重画都能还原正确界面
- 入口只转交:平台受限入口不堆业务,逻辑全在处理层。
- 收包分发只分发:一张
rpc → 处理器路由表,不在分发口写业务。 - 数据优先、表现延后:先落状态模型,再由表现层派生;重连=重画,与正常对局复用同一重画路径。
2.3 依赖方向自检
- 有没有"下层反过来 import/引用上层"?有 → 边界错位,重划。
- 有没有"两个模块互相依赖"?有 → 抽公共依赖或合并职责。
- 有没有"入口层里写了算法/规则"?有 → 下沉到领域层。
- 有没有"表现层里存了业务真相"?有 → 上移到状态层。
3. 本篇小结
- 七大总则:SSOT、单向依赖、职责单一、关注点分离、OCP、配置优先、显式失败。
- 后端六层(入口/收发/编排/领域/数据/共享)、前端六层(入口/分发/处理/状态/表现/共享),依赖单向向下。
- 层是稳定的,层内组织自定;判断对错的尺子始终是依赖方向与职责归属。
下一篇 02-可扩展性与配置化:把 OCP 与"配置优先"落成具体模式与判据。