训练进度
-已完成 2 个节点
- 查看详情 -diff --git a/docs/technical-development/React.md b/docs/technical-development/React.md
new file mode 100644
index 0000000..af0974d
--- /dev/null
+++ b/docs/technical-development/React.md
@@ -0,0 +1,12 @@
+---
+title: React 学习资料
+status: unread
+direction: technical-development
+---
+
+# React 学习资料
+
+## 课程讲义
+
+- [React(第一次)](assets/react-session-1.pdf)
+- [React(第二次)](assets/react-session-2.pdf)
diff --git a/docs/technical-development/assets/CSS.pdf b/docs/technical-development/assets/CSS.pdf
new file mode 100644
index 0000000..23f77b3
Binary files /dev/null and b/docs/technical-development/assets/CSS.pdf differ
diff --git a/docs/technical-development/assets/HTML.pdf b/docs/technical-development/assets/HTML.pdf
new file mode 100644
index 0000000..e82e0bd
Binary files /dev/null and b/docs/technical-development/assets/HTML.pdf differ
diff --git a/docs/technical-development/assets/react-session-1.pdf b/docs/technical-development/assets/react-session-1.pdf
new file mode 100644
index 0000000..b162a9d
Binary files /dev/null and b/docs/technical-development/assets/react-session-1.pdf differ
diff --git a/docs/technical-development/assets/react-session-2.pdf b/docs/technical-development/assets/react-session-2.pdf
new file mode 100644
index 0000000..83cd948
Binary files /dev/null and b/docs/technical-development/assets/react-session-2.pdf differ
diff --git a/docs/technical-development/backend-database-mysql-prisma.md b/docs/technical-development/backend-database-mysql-prisma.md
index 5ff7d83..966518f 100644
--- a/docs/technical-development/backend-database-mysql-prisma.md
+++ b/docs/technical-development/backend-database-mysql-prisma.md
@@ -6,11 +6,42 @@ direction: technical-development
# 数据库、MySQL 与 Prisma
-## 关系型数据库
+> 本文整合自“产研后端第二次内训-数据库入门”讲义(作者:仙人掌),并补充了可直接练习的 SQL 和 Prisma 示例。
-数据库保存结构化数据,表由行和列组成。主键唯一标识一行,外键表达表之间的关系。常见关系包括一对一、一对多和多对多。
+## 数据库是什么
+
+数据库是用来保存和管理数据的软件系统。它帮助程序有条理地存储、查询和修改数据,而不必把所有内容都塞进普通文本文件中。
+
+### 常见的数据存储方式
+
+- **关系型数据库(重点掌握)**:数据按表组织,表由行和列组成。表可以通过主键和外键建立关系。常见系统有 SQLite、MySQL、SQL Server 和 PostgreSQL。结构清晰,适合数据之间有明确关系的业务。
+- **文档数据库(延伸了解)**:常以 JSON 文档保存数据。不同文档可以有不同字段,结构较灵活,适合字段会随业务变化的场景。
+- **键值存储(了解)**:按 `key -> value` 保存和读取数据。Redis 是常见例子。原讲义此处另有示例文字 `Redl/sql-tutorial.html`,看起来不是有效链接,因此只保留为原文备注。
+
+本篇重点学习关系型数据库、MySQL、SQL 和 Prisma。
+
+## 关系型数据库基础
+
+表可以理解为一组结构相同的记录。每一行是一条记录,每一列描述一种属性。以待办事项为例:
+
+| id | title | completed |
+| --- | --- | --- |
+| 1 | 阅读文档 | false |
+| 2 | 完成练习 | true |
+
+- **主键**(Primary Key)唯一标识一行,例如 `id`。
+- **外键**(Foreign Key)引用另一张表的主键,用来表示表之间的关系。
+- 常见关系有一对一、一对多和多对多。例如,一个用户可以有多条待办事项,就是一对多关系。
+
+列需要选择合适的数据类型,例如整数 `INT`、字符串 `VARCHAR`、布尔值 `BOOLEAN` 和时间 `TIMESTAMP`。约束用于限制数据,例如 `NOT NULL` 表示不能为空,`DEFAULT` 指定默认值。
+
+## SQL 入门
+
+SQL 是操作关系型数据库的常用语言。基本流程包括创建数据库和表、写入数据、查询数据、修改数据和删除数据。常见命令有 `CREATE`、`SELECT`、`INSERT`、`UPDATE` 和 `DELETE`,合称 CRUD(创建、读取、更新、删除)。
```sql
+CREATE DATABASE training;
+
CREATE TABLE todo (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL,
@@ -18,14 +49,57 @@ CREATE TABLE todo (
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-SELECT id, title FROM todo WHERE completed = FALSE ORDER BY created_at DESC;
+INSERT INTO todo (title) VALUES ('阅读数据库文档');
+
+SELECT id, title
+FROM todo
+WHERE completed = FALSE
+ORDER BY created_at DESC;
+
+UPDATE todo
+SET completed = TRUE
+WHERE id = 1;
+
+DELETE FROM todo
+WHERE id = 1;
+```
+
+`WHERE` 用来筛选目标记录。执行 `UPDATE` 或 `DELETE` 前要确认筛选条件;漏掉 `WHERE` 可能会修改或删除整张表的数据。程序写入数据时使用参数化查询,不要把用户输入直接拼接进 SQL,以避免 SQL 注入。索引应服务于实际查询;索引太多会增加写入和维护成本。
+
+SQL 数据类型、主键和外键约束、`SELECT ... WHERE`、`INSERT INTO`、`UPDATE` 和 `DELETE` 都是后端开发的基础内容。讲义推荐的 SQL 入门资料:
+
+- [MySQL 创建数据库教程](https://www.runoob.com/mysql/mysql-create-database.html)
+- 原讲义还列有一个 SQL 教程地址:`https://www.runoob.com/sqzju课程:数据库系统`。该地址格式异常,按原文记录,未转换成可点击链接。
+- 深入学习关系型数据库可查阅《数据库系统概念》。原讲义中的第三方镜像地址为 `https://zh.singlelogin.re/book/5668770/6f85ac/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E6%A6%82%E5%BF%B5-%E5%8E%9F%E4%B9%A6%E7%AC%AC6%E7%89%88.html`;按原文保留为文字,不设为可点击入口。
+
+## MySQL:服务端与连接
+
+MySQL 通常以后台服务的形式运行,负责接收请求并读写数据。Workbench 是图形化客户端;命令行工具也是客户端。客户端连接 MySQL 服务后,发送 SQL,由服务端执行并返回结果。Windows 上安装 MySQL 时,可以分别理解为后台服务和用于连接它的工具。
+
+连接数据库时需要指定协议、用户名、密码、主机、端口和数据库名称。常见连接字符串形式如下:
+
+```text
+mysql://USER:PASSWORD@HOST:PORT/DATABASE
+```
+
+例如:
+
+```text
+mysql://janedoe:mypassword@localhost:5432/mydb?connection_limit=5
```
-写入数据时使用参数化查询,避免把用户输入拼接进 SQL。索引应服务于真实查询,过多索引会增加写入成本。
+其中 `USER` 和 `PASSWORD` 是登录凭据,`HOST` 和 `PORT` 指向数据库服务,`DATABASE` 是要使用的数据库,问号后的部分是连接参数。上例中的用户名和密码只是示例。不要把包含真实密码的连接字符串提交到 Git 仓库。
+
+讲义列出的 MySQL 安装参考文章如下,具体步骤可能因系统和版本而异:
+
+- [MySQL 安装参考(CSDN)](https://blog.csdn.net/bobo553443/article/details/81383194)
+- [MySQL 安装参考(博客园)](https://www.cnblogs.com/oukele/p/10642061.html)
-## Prisma
+## ORM 与 Prisma
-Prisma 用 schema 描述数据模型,并生成类型安全的客户端:
+ORM 是 Object-Relational Mapping(对象关系映射)。它把关系型数据库中的表映射为程序中的类或模型,把表中的行映射为对象,让程序能通过代码读写数据,而不必在每处都手写 SQL。TypeORM 是一种 ORM 工具,感兴趣时可阅读[相关文档](https://typeorm.bootcss.com/)。
+
+Prisma 是数据库工具集,包含 ORM 能力,并根据 schema 生成类型安全的客户端。开发者在 Prisma schema 中描述模型,再通过客户端查询和修改数据:
```prisma
model Todo {
@@ -36,9 +110,42 @@ model Todo {
}
```
-典型流程:配置 `DATABASE_URL` → 编写 schema → 创建迁移 → 生成客户端 → 在服务层调用客户端。迁移文件应提交到 Git,生产环境不要随意重置数据库。
+典型流程是:配置 `DATABASE_URL` → 编写 schema → 创建数据库迁移 → 生成客户端 → 在服务层调用客户端。迁移(migration)用于记录并应用数据库结构的变化,例如创建表或修改列。迁移文件应提交到 Git;不要在生产数据库上随意重置或删除数据。
+
+讲义列出的 Prisma 参考资料:
+
+- [Prisma 中文文档站](https://prisma.nodejs.cn/)
+- [MySQL 数据库配置](https://prisma.nodejs.cn/orm/overview/databases/mysql)
+- [从头开始:TypeScript 与 MySQL](https://prisma.nodejs.cn/getting-started/setup-prisma/start-from-scratch/relational-databases-typescript-mysql)
+- [Prisma Client 增删改查(CRUD)](https://prisma.nodejs.cn/orm/prisma-client/queries/crud)
+
+## 综合练习:题目管理系统
+
+实现一个题目管理系统。程序可以从命令行接收命令,也可以从文件读取命令;为了方便观察执行结果,可以在处理每条命令后暂停约一秒。命令的具体输入格式可以自行设计,但功能需要完整。
+
+基础功能:
+
+1. **添加单选题**:输入题干、选项数量、各选项和正确选项;创建成功后输出题目 ID。
+2. **添加多选题**:输入题干、选项数量、各选项、正确答案数量和正确选项;创建成功后输出题目 ID。
+3. **删除题目**:根据题目 ID 删除一题。
+4. **查询题目**:根据题目 ID 展示题干和选项。
+5. **回答题目**:输入题目 ID 和答案,输出 `Right Answer` 或 `Wrong Answer`。
+
+基础质量要求:
+
+- 能完成上述操作。
+- 代码结构清楚、命名易懂,并写必要且有用的注释。
+
+进阶要求(选做):
+
+- 修改题目:根据题目 ID 修改题干、选项或答案。
+- 使用日志框架,并将日志输出到文件。
+- 支持 `insert question filename.json` 一类的命令,从 JSON 文件读取并添加一道题。
+- 支持 `execute filename.txt`,从文本文件批量读取并执行多条管理命令。也可以扩展为读取文件中的数据并一次性批量导入。
+
+开始实现前,先设计题目和选项的数据结构,再决定表之间的关系。一个题目有多个选项,通常可拆成题目表和选项表;查询或回答时通过题目 ID 找到相应选项和正确答案。
-## 练习
+## 其他练习
- [ ] 为“用户—待办”设计表结构,并说明主键和外键。
- [ ] 写出查询未完成待办、创建待办和更新状态的 SQL。
diff --git a/docs/technical-development/backend-oop-typescript.md b/docs/technical-development/backend-oop-typescript.md
index 58d2a8e..253c209 100644
--- a/docs/technical-development/backend-oop-typescript.md
+++ b/docs/technical-development/backend-oop-typescript.md
@@ -6,55 +6,330 @@ direction: technical-development
# 后端面向对象与 TypeScript
-面向对象把问题中的实体抽象为对象:对象拥有状态(属性)和行为(方法),相同结构的对象由类描述。
+> 本文整合自“产研后端第一次内训-面向对象程序设计”讲义(作者:仙人掌),并补充了 TypeScript 示例。讲义中的 Flutter/Dart 代码截图用于说明代码规范;本文用 TypeScript 重写相关示例。
-## 类、封装与继承
+## 写代码时先注意这些
+
+### 命名与注释
+
+- 变量和函数使用 `camelCase`,例如 `playerName`、`getPlayer()`。
+- 类、接口和类型使用 `PascalCase`,例如 `Player`、`Animal`。
+- 常量通常使用全大写加下划线,例如 `MAX_HP`。
+- 注释用来解释意图和复杂逻辑,不要逐行复述代码。普通行内说明使用 `//`,较长说明可以使用 `/* ... */` 或文档注释。
+- 用 `TODO` 标出尚未完成的功能,用 `FIXME` 标出已知问题,并写清具体事项;不要让它们代替真正的修复。
+
+```ts
+// TODO: 支持玩家切换武器
+// FIXME: 离开房间后需要重置当前房间状态
+```
+
+### 结构、日志与测试
+
+- 尽量减少多层嵌套。多个明确的分支可以用 `switch` 表达;把长函数拆成职责清楚的小函数。
+- 一行不要塞入太多逻辑,但也不必为了短行把一个表达式拆成许多行;优先保证容易阅读。
+- 调试时不要到处留下 `console.log`。项目中应选用日志框架,在关键流程按需要记录 `debug`、`info`、`warn` 或错误信息,并输出到合适的位置。
+- 功能完成后,在有余力时为关键逻辑补充单元测试,检查实际结果是否符合预期。
+
+### npm 包管理器
+
+JavaScript 和 TypeScript 项目常用 npm 管理依赖和运行脚本。讲义提供了两篇入门参考:[npm 包管理器文章(CSDN)](https://blog.csdn.net/2301_79985178/article/details/140573837)和[知乎专栏](https://zhuanlan.zhihu.com/p/686389408)。
+
+## 面向过程与面向对象
+
+面向过程(Procedure Oriented)关注解决问题的步骤:先把任务拆成函数,再按顺序调用这些函数。它开销小、执行直接,适合流程清楚、性能要求高的场景。
+
+面向对象(Object Oriented)把问题中的实体抽象成对象,由对象保存状态并提供行为。它适合围绕业务实体组织较大的程序,便于分工和扩展。使用哪种方式要看问题本身;面向对象并不会自动让程序更快或更简单。
+
+设计面向对象程序时,通常先找出需要操作的对象,再明确对象的属性、行为,以及对象之间的关系(也叫数据建模)。复杂业务中也可以先用 UML 图梳理角色和关系。
+
+## 类、对象与实例
+
+类描述一类对象共有的属性和方法;根据类创建出的具体对象叫实例。下面用汽车举例:
+
+```ts
+class Car {
+ engine: string
+
+ constructor(engine: string) {
+ this.engine = engine
+ }
+
+ display(): void {
+ console.log(`发动机为:${this.engine}`)
+ }
+}
+
+const car = new Car('Engine 1')
+car.display()
+```
+
+`engine` 是属性,`display` 是方法,`new Car(...)` 创建了一个 `Car` 实例。
+
+## 继承与方法重写
+
+继承表示一个类在已有类的基础上扩展能力。已有类叫父类或基类,新类叫子类或派生类。TypeScript 使用 `extends` 声明继承;子类可以调用 `super` 访问父类构造函数或方法,也可以重写方法:
+
+```ts
+class Printer {
+ print(): void {
+ console.log('父类的 print 方法')
+ }
+}
+
+class StringPrinter extends Printer {
+ override print(): void {
+ super.print()
+ console.log('子类的 print 方法')
+ }
+}
+
+const printer: Printer = new StringPrinter()
+printer.print()
+```
+
+继承适合表达明确的“是一种”关系。若只是想共享少量能力,接口或组合通常更灵活。
+
+## 封装与访问控制
+
+封装把对象的状态和操作集中在类中,并限制外部随意改动内部状态。外部通过公开方法与对象交互,类可以在这些方法中检查输入并维持自身状态的有效性。
+
+TypeScript 常用以下访问控制修饰符:
+
+- `public`:公开访问;默认访问级别。
+- `protected`:类自身和子类可以访问。
+- `private`:只允许定义它的类访问。
```ts
class Student {
private grade = 0
- constructor(public readonly name: string, private readonly studentId: string) {}
+ constructor(public readonly name: string) {}
setGrade(value: number): void {
- if (value < 0 || value > 100) throw new Error('成绩必须在 0 到 100 之间')
+ if (value < 0 || value > 100) {
+ throw new Error('成绩必须在 0 到 100 之间')
+ }
this.grade = value
}
- getGrade(): number { return this.grade }
+ getGrade(): number {
+ return this.grade
+ }
}
+
+const student = new Student('小明')
+student.setGrade(90)
+console.log(student.getGrade())
+// student.grade = 101 // 编译错误:grade 是 private
```
-`private` 隐藏实现细节,公共方法提供受控接口。继承用 `extends` 表达“是一个”关系,子类通过 `super` 调用父类构造函数;如果只是共享能力,优先考虑接口和组合。
+`readonly` 属性只能在声明时或构造函数中赋值,之后不能重新赋值。接口中也可以声明只读属性和可选属性,见下文。
-## 接口与多态
+## 多态
+
+多态指不同对象可以响应同一个操作,但各自给出不同实现。调用方使用共同的接口,不必知道对象内部的具体类型:
```ts
-interface Notifier { send(message: string): void }
+interface Notifier {
+ send(message: string): void
+}
class ConsoleNotifier implements Notifier {
- send(message: string): void { console.log(message) }
+ send(message: string): void {
+ console.log(message)
+ }
}
+
+function notify(notifier: Notifier, message: string): void {
+ notifier.send(message)
+}
+
+notify(new ConsoleNotifier(), '任务完成')
```
-调用方只依赖 `Notifier`,因此可以替换具体实现。接口还能描述请求体、数据库记录等数据结构。
+同一个 `send` 调用可以由不同通知方式实现,例如控制台、邮件或其他服务。
+
+## TypeScript 接口
+
+TypeScript 的 `interface` 描述对象应具有的属性、方法及其类型。它能检查对象形状是否符合约定,让错误更早出现在编译阶段。接口本身不会生成运行时对象。
+
+### 描述对象结构
+
+```ts
+interface User {
+ id: number
+ name: string
+ email: string
+}
+
+const user: User = {
+ id: 1,
+ name: 'Alice',
+ email: 'alice@example.com',
+}
+```
+
+`User` 规定对象要包含 `id`、`name` 和 `email`,并且类型要相符。
+
+### 约束类的实现
+
+类使用 `implements` 表示自己遵守某个接口。编译器会检查类是否提供了接口要求的属性和方法:
+
+```ts
+interface Animal {
+ name: string
+ makeSound(): void
+}
+
+class Dog implements Animal {
+ constructor(public name: string) {}
+
+ makeSound(): void {
+ console.log('Woof!')
+ }
+}
+
+const dog = new Dog('Buddy')
+dog.makeSound()
+```
+
+### 描述函数类型
+
+接口也可以约定函数的参数和返回值:
+
+```ts
+interface Greet {
+ (name: string): string
+}
+
+const sayHello: Greet = (name) => `Hello, ${name}`
+console.log(sayHello('Alice'))
+```
+
+### 结构类型与鸭子类型
+
+TypeScript 主要按结构判断类型:对象只要具有所需的属性和方法,就可以传给相应函数,不要求它必须继承某个特定类。这种方式也称为鸭子类型。
+
+```ts
+interface Point {
+ x: number
+ y: number
+}
+
+function addPoints(p1: Point, p2: Point): Point {
+ return { x: p1.x + p2.x, y: p1.y + p2.y }
+}
+
+const result = addPoints({ x: 3, y: 4 }, { x: 5, y: 1 })
+// addPoints({ x: 1 }, { x: 4, y: 3 }) // 编译错误:缺少 y
+```
+
+### 可选属性与只读属性
+
+在属性名后加 `?` 表示该属性可以省略;加 `readonly` 表示初始化后不能重新赋值:
+
+```ts
+interface Vehicle {
+ readonly make: string
+ model: string
+ year?: number
+}
+
+const vehicle: Vehicle = { make: 'Toyota', model: 'Corolla' }
+vehicle.model = 'Camry' // 可以修改
+// vehicle.make = 'Honda' // 编译错误:make 是只读属性
+```
+
+### 接口继承
+
+接口可以通过 `extends` 组合。子接口会包含父接口的要求,并能添加自己的属性:
+
+```ts
+interface Person {
+ name: string
+}
+
+interface Employee extends Person {
+ employeeId: number
+}
+
+const employee: Employee = { name: 'Alice', employeeId: 12345 }
+```
+
+### 为第三方 JavaScript 库补充类型
+
+有些 JavaScript 库没有内置 TypeScript 类型。可以通过类型声明描述库提供的对象和方法,让 TypeScript 代码获得类型检查。讲义将其列为扩展了解内容;实际使用时优先查找该库维护者提供的类型声明。
+
+## 面向对象的主要特性
+
+- **封装(Encapsulation)**:把数据和操作集中在对象中,通过明确的接口访问状态,避免外部代码随意改动内部实现。
+- **继承(Inheritance)**:让子类沿用并扩展父类的能力,适用于明确的类型层级。
+- **多态(Polymorphism)**:不同实现通过同一接口提供相同操作,调用方不必依赖具体实现。
+
+## 面向对象设计原则:SOLID
+
+这些原则帮助代码保持职责清楚、便于扩展。它们是设计时的参考,不是每段代码都必须强行套用的规则。
+
+- **单一职责原则(SRP, Single Responsibility Principle)**:一个类或模块聚焦一项职责,避免一个类包办许多互不相关的功能。
+- **开闭原则(OCP, Open-Closed Principle)**:对扩展开放、对修改关闭。新增客户端能力时,尽量通过抽象扩展,而不是反复改动稳定的服务端实现。
+- **里氏替换原则(LSP, Liskov Substitution Principle)**:子类应能替换父类使用,并遵守父类对行为的约定。例如,若所有员工都能参加年会抽奖,新员工也应遵守同一规则。
+- **依赖倒置原则(DIP, Dependency Inversion Principle)**:高层业务依赖抽象,具体实现依赖同一抽象;不要让核心逻辑直接绑定某个底层实现。
+- **接口隔离原则(ISP, Interface Segregation Principle)**:调用方不应依赖用不到的接口。把大而全的接口拆成调用方真正需要的小接口。
+
+## 综合练习
+
+下面两个作业来自讲义。重点是练习对象建模、接口、继承和设计原则;命令和输出可以自行调整。
+
+### T1:龙与魔法(基础)
+
+用 TypeScript 实现一个简单的战斗规则。讲义认为此题的设计空间较大,建议有余力的同学挑战 T2。
+
+角色与规则:
+
+- 玩家可以是战士(`Fighter`)、法师(`Mage`)或龙骑士(`Dragoon`)。
+- 怪物可以是兽人(`Orc`)、精灵(`Elf`)或龙(`Dragon`);怪物有血量。
+- 战士受到兽人攻击时,伤害减半。
+- 精灵受到法师攻击时,伤害减半。
+- 主程序创建若干玩家和怪物,让双方可以互相攻击,并能观察攻击后的血量等结果。
+
+基础要求:代码风格清楚、注释有用,并能查看攻击后的结果。
+
+选做扩展:
+
+- 给玩家增加护甲,不同类型的护甲提供不同效果。
+- 增加武器,例如剑(`Sword`)和法杖(`Staff`);玩家可装备或切换武器。武器有攻击力和伤害类型,例如物理或火焰,也可以设计更细的类型。
+- 增加规则:兽人受到物理攻击时伤害减半;精灵受到冰属性攻击时伤害减半;龙免疫物理和魔法攻击,但龙骑士攻击龙时可以造成双倍伤害。
+- 使用日志框架记录战斗过程并写入文件。
+
+### T2:Adventure 命令行游戏(进阶)
+
+实现一个命令行冒险游戏。玩家要探索城堡中的房间,找到被关押的公主,并带她离开城堡。可以有多个楼层和多个房间;每种房间有自己的出口。
+
+游戏规则:
+
+- 玩家从大厅开始。程序显示当前房间名称、出口数量和出口名称,例如:
+
+ ```text
+ Welcome to the lobby. There are 3 exits: east, west and up.
+ Enter your command:
+ ```
-## SOLID 与代码规范
+- 玩家通过 `go east` 一类的命令选择出口,进入相邻房间后,程序继续显示该房间的信息。
+- 城堡中有多个房间,其中一间有怪物,怪物的具体位置未知。玩家进入怪物所在房间时,游戏结束。
+- 公主在一间秘密房间里。玩家找到她后会看到对话,并与她一起离开。
+- 离开城堡的唯一出口是大厅;找到公主后,玩家还需要找到返回大厅的路线。
+- 输入和输出都使用英文。
-- 单一职责:一个模块只有一个主要变化原因。
-- 开闭原则:增加行为时优先扩展,不随意修改稳定代码。
-- 里氏替换:子类应遵守父类的行为约定。
-- 接口隔离:小接口比一个包揽所有能力的大接口更易维护。
-- 依赖倒置:业务逻辑依赖抽象,基础设施实现抽象。
+基础要求:代码风格清楚、注释有用;至少有 3 种不同房间,房间总数至少为 5;公主和怪物的位置每次随机决定。
-变量和函数使用 `camelCase`,类、接口和类型使用 `PascalCase`。关键逻辑写注释,调试信息使用项目的日志工具。
+选做扩展:房间总数由用户输入或配置文件决定;使用日志框架并输出到文件;支持多层城堡。
-## 练习
+## 原讲义参考链接
-- [ ] 为命令行冒险游戏设计 `Room`、`Player` 和 `Monster` 类。
-- [ ] 用接口抽象存储层,让内存存储和数据库存储可以互换。
-- [ ] 写一个测试,验证成绩校验和异常信息。
+- [npm 包管理器文章(CSDN)](https://blog.csdn.net/2301_79985178/article/details/140573837)
+- [npm 包管理器文章(知乎)](https://zhuanlan.zhihu.com/p/686389408)
+- [面向对象设计原则(CSDN)](https://blog.csdn.net/qq_34760445/article/details/82931002)
## 学习衔接
-在[TypeScript 基础](environment-typescript.md)之后练习业务建模,再学习[HTTP、API 与爬虫](backend-http-api.md);需求关系可参考[UML 建模](../product-operations/uml.md)。
+先学习[TypeScript 基础](environment-typescript.md),再用这些概念练习业务建模,然后学习[HTTP、API 与爬虫](backend-http-api.md);需求和对象关系可参考[UML 建模](../product-operations/uml.md)。
diff --git a/docs/technical-development/frontend-html-css.md b/docs/technical-development/frontend-html-css.md
index c8558db..5cdaa8d 100644
--- a/docs/technical-development/frontend-html-css.md
+++ b/docs/technical-development/frontend-html-css.md
@@ -6,23 +6,38 @@ direction: technical-development
# HTML 与 CSS
+HTML 负责页面内容和结构,CSS 负责外观和布局。浏览器读取两者后显示网页。做页面时,先用 HTML 把内容和层级写清楚,再用 CSS 调整样式。
+
## HTML:页面结构
-HTML 是标记语言,用元素表达页面结构。一个元素通常由开始标签、内容和结束标签组成;属性用于补充元素信息。
+HTML 是标记语言,用元素表达页面结构。大多数元素由开始标签、内容和结束标签组成,属性用于补充信息。新建页面时,可以从下面的基本结构开始:
```html
- 已完成 2 个节点训练进度
-
已完成 2 个节点
+ 查看详情 +