03-游戏拆解与组装
游戏拆解与组装(非 ECS)
「游戏拆解与组装」讲的是一套非 ECS 的拆解与组装案例:游戏程序拆成 Engine(支撑子系统)与 Game(业务子系统),再由 GameApplication 组装。Engine 负责「怎么运行」,Game 负责「运行什么」——这是拆解与组织原则在游戏上的完整应用,不依赖 ECS。这一条线就是这个案例本身:游戏怎么拆、怎么组。
一、先把「支撑子系统 / 业务子系统 / 调度组装」分开一个游戏程序可以抽象成两个子系统:
123游戏程序├── Engine 子系统 ← 支撑└── Game 子系统 ← 业务
12345Engine├── ECS / Rendering / Physics / Input / Audio / Resource / SceneGame├── Player / Enemy / Weapon / Character / Inventory / Quest / GameRule
Engine 是支撑子系统,Game 是业务子系统。 这是游戏拆解的第一刀——把「怎么运行游戏」和「游戏内容是什么」 ...
02-边界-拆分的依据
边界:拆分的依据
拆分从来不是「因为大了所以拆」。拆分是沿着边界切——先识别出两个部分之间的分界线在哪,再动手。入口与业务的拆分是边界,系统拆子系统也是边界,函数拆函数、文件拆文件同样是边界。边界贯穿所有粒度,而且边界不止一种:职责边界、变化边界、生命周期边界、依赖边界、物理边界。系统拆分只是边界的一种应用,不是全部。
一、拆分不是按大小,是按边界很多人理解拆分是「代码太长就拆」「文件太大就拆」。但核心原则反复强调:
职责决定拆分,重复决定封装,边界决定分层,依赖决定接口。
为什么不是按大小拆?因为「长」不是拆分理由,「边界在哪」才是:
12345678一个 1000 行的文件,但只做一件事 → 不该拆(没有边界)一个 200 行的文件,同时做「解析参数」和「扫描内存」 → 该拆(有明确的职责边界)一个函数同时处理「玩家移动」和「碰撞检测」 → 该拆(两个职责之间有边界)
拆分 = 找到边界,沿边界切。 大小只是表面现象,边界才是依据。
二、边界的类型边界不是一种,至少有五类。每一类回答不同的问题:
1. 职责边界——「是不是在做好几件事」12一件事 → ...
01-拆解与组织原则
拆解与组织原则
所有架构的底层是同一个动作:拆解(把复杂系统拆成组成部分)和组织(把拆出来的部分重新组装成系统)。这一对动作不专属于软件——游戏、逆向、语言、认知都一样适用。它是所有「线」共享的元原则,而系统拆分、边界、ECS 都只是它的一次具体应用。
一、两个方向:拆解与组织面对任何复杂系统,只有两个基本动作:
12345复杂系统 ↓ 拆解(解决复杂度)组成部分 ↓ 组织(解决怎么拼)完整系统
拆解回答「这个系统由什么组成」:
12345Server├── Network Runtime Socket / Connection / Buffer / EventLoop├── Protocol Decoder / Encoder├── Dispatch Router / Handler└── Application Service / Domain / Algorithm
组织回答「这些部分怎么拼成系统」:
12345libnetwork / libprotocol / libdatabase ...
04-头文件-依赖关系的静态表达
头文件——依赖关系的静态表达
依赖关系在代码里有两个层面的表现:运行期的动态调用(A 调用 B 的函数)和编译期的静态包含(A 包含 B 的头文件)。头文件是依赖关系的静态表达——它把「谁依赖谁」写在文件层面,不运行就能看到。这一条线:头文件如何表达依赖、它表达了什么依赖、不表达什么依赖。
一、依赖的两种表现:动态调用 vs 静态包含12运行期依赖(动态):A 调用 B 的函数 → 程序运行时才发生静态依赖(编译期):A include B 的头文件 → 编译时就能看到
123456// a.c#include "b.h" // 静态依赖:a.c 依赖 b.h(编译期可见)void a_func() { b_func(); // 动态依赖:a.c 调用 b 的函数(运行期发生)}
静态包含是动态调用的前提——如果不包含 b.h,连 b_func 都声明不了,更谈不上调用。所以头文件表达的是「能依赖什么」,调用表达的是「实际依赖了什么」。
二、头文件表达的三层依赖1. 包含关系 = 编 ...
03-依赖接口
依赖接口——组件依赖的是接口而非实现
依赖注入解决的是「同一实例怎么共享」,依赖接口解决的是「组件依赖谁」。这两个问题经常被混为一谈,但它们是完全不同的维度:一个管传递,一个管依赖方向。依赖接口是独立于依赖注入的另一条线。
一、两个问题,两个维度12345问题 1:组件 A 需要用组件 B,B 的实例从哪来? → 这是依赖注入要解决的(传递维度)问题 2:组件 A 需要用组件 B,A 依赖的是 B 的接口还是 B 的实现? → 这是依赖接口要解决的(依赖维度)
两个问题可以独立变化:
1234567891011场景 1:依赖实现 + 构造函数传参 → A 直接用 B 的具体类,通过构造函数传入 → 依赖了实现,但用了注入场景 2:依赖接口 + 全局变量 → A 用 IB 接口,通过全局变量获取 → 依赖了接口,但没用注入场景 3:依赖接口 + 构造函数传参 → A 用 IB 接口,通过构造函数传入 → 既依赖接口,又用了注入
依赖接口和依赖注入是两个独立的维度,可以任意组合。
二、依赖实现 vs 依赖接口1234567891011121314// 依赖实现:A ...
02-依赖注入
依赖注入——同一实例多处调用时怎么共享
虚函数解决了「怎么定义接口」,但还有一个问题:如果三个地方都需要用同一个 AuthService 实例,这个实例从哪来?怎么传过去?这就是依赖注入要解决的问题。依赖注入不是一种设计模式,而是「共享同一实例」的四种机制的总称。
一、问题:同一实例需要多处调用假设有一个日志系统,多个模块都需要用它:
12345678910111213141516171819class LogSystem {public: void info(const char* msg); void error(const char* msg);};class AuthService { LogSystem& log_; // 需要日志public: AuthService(LogSystem& log) : log_(log) {} void login() { log_.info("login"); }};class Netw ...
01-依赖关系的演化
依赖关系的演化——从隐式调用到显式边界
依赖关系是软件中最基本的关系——A 用到了 B,A 就依赖 B。但依赖在每个阶段的形态完全不同:函数级是隐式的,文件级是 include,分层后变成单向约束,系统拆分后变成接口边界,多系统后变成包依赖和构建依赖。这一篇把依赖关系的完整演化讲清楚。
一、什么是依赖一句话定义:A 需要 B 才能工作,A 就依赖 B。
1234函数 A 调用了函数 B → A 依赖 B文件 A include 了文件 B 的头文件 → A 依赖 B模块 A 使用了模块 B 的数据结构 → A 依赖 B系统 A 通过网络调用了系统 B → A 依赖 B
依赖的本质:没有 B,A 就不能工作。
二、函数级:隐式依赖函数之间的依赖是隐式的——你调用了谁,你就依赖了谁,不需要声明:
12345void do_scan() { int fd = open("file.bin", O_RDONLY); // 依赖 open search_pattern(data, len); // 依赖 search_ ...
00-总纲·知识地图
知识地图与总纲
本目录下有二十二条独立知识线(其中「依赖关系」「拆解与组织」「正向建模与逆向应用」「系统角色组成」「单一职责」「设计」「工程控制」「图像与绘画」「认知与语言」「桌面端架构」「模块与构建单元」「游戏」「业务分析与领域」「最小闭环」是十四个主题)。每条是一篇或多篇完整的文章。线与线之间独立,互补,不串在一起。
文章列表
#
文章
一条什么线
1
从指令到系统/01-从指令到业务系统.md
第一条演化线:指令→结构→函数→文件→分层→业务系统(由模块组成)
2
从指令到系统/02-从函数到网络系统.md
第二条演化线:socket→循环→多连接→EventLoop→协议→会话→网络(由组件组成)
3
从指令到系统/03-多系统组成的网络通信软件.md
第三条演化线:业务系统+网络系统+入口系统→三系统协作的网络通信软件
4
七条流/(5 篇)
行为分析十个维度,按演化阶段展开:单函数→单文件→多文件→多层→多系统,每篇覆盖十条流在该阶段的形态。用户流程在 CLI 阶段是一类多条(每条命令一个实例),到 GUI 才成为真正的线(见 6 从输入到交互)
...
101.使用Grop网站提供的api
在不同环境中调用api1.创建api key
创建api key 在gropapi.com注册账号,登录后创建一个新的api,填写相关信息后保存,系统会生成一个唯一的api key。
保存api key gropapikey1:gsk_开头的一串字符串
1gsk_开头的一串字符串
2. crul调用api使用curl发送请求查看所有可用模型
打开终端环境
运行curl带参数123curl -X GET "https://api.groq.com/openai/v1/models" \ -H "Authorization: Bearer gsk_开头的一串字符串" \ -H "Content-Type: application/json"
3.查看结果
curl调用免费模型
打开终端环境
输入命令123456789101112 curl https://api.groq.com/openai/v1/chat/completions \-H "Content-Type: application/json&qu ...
光猫开telnet与配置
贝尔XG-140W-TD开telnet与设置wifi名称
访问链接开启telnet
http://192.168.1.1:8080/system.cgi?telnet
使用telnet连接
1telnet 192.168.1.1
账号密码登录在机器背面
12user:useradminpass:zyhfn
提权到root
1su useradmin_ftp
设置wifi名称
12cfgcli -s InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID "meifushe2"cfgcli -s InternetGatewayDevice.LANDevice.1.WLANConfiguration.2.SSID "meifushe5"
中兴F650A光猫开telnet与修改超级密码1. 准备工作
备份loid与宽带账号密码
初始化光猫
下载工具https://github.com/Septrum101/zteOnu
设置电脑ip地址为:00:07:29:55:35:57.
使用 ...
