<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Design on Zata-砸它</title><link>https://www.zata.cc/categories/design/</link><description>Recent content in Design on Zata-砸它</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>Example Person</copyright><lastBuildDate>Sun, 12 Apr 2026 21:27:00 +0800</lastBuildDate><atom:link href="https://www.zata.cc/categories/design/index.xml" rel="self" type="application/rss+xml"/><item><title>领域驱动设计（DDD）分层架构：用领域语言构建复杂系统</title><link>https://www.zata.cc/p/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1ddd%E5%88%86%E5%B1%82%E6%9E%B6%E6%9E%84%E7%94%A8%E9%A2%86%E5%9F%9F%E8%AF%AD%E8%A8%80%E6%9E%84%E5%BB%BA%E5%A4%8D%E6%9D%82%E7%B3%BB%E7%BB%9F/</link><pubDate>Sun, 12 Apr 2026 12:00:00 +0800</pubDate><guid>https://www.zata.cc/p/%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1ddd%E5%88%86%E5%B1%82%E6%9E%B6%E6%9E%84%E7%94%A8%E9%A2%86%E5%9F%9F%E8%AF%AD%E8%A8%80%E6%9E%84%E5%BB%BA%E5%A4%8D%E6%9D%82%E7%B3%BB%E7%BB%9F/</guid><description>&lt;h2 id="什么是领域驱动设计">什么是领域驱动设计？
&lt;/h2>&lt;p>&lt;strong>领域驱动设计（Domain-Driven Design，DDD）&lt;/strong> 由 Eric Evans 在 2003 年提出。它的核心思想是：&lt;strong>让软件模型与业务模型保持一致&lt;/strong>——代码中的术语、结构、行为，应该直接反映业务专家的语言。&lt;/p>
&lt;p>DDD 不是一套框架，而是一套&lt;strong>思想方法&lt;/strong>，包含两大部分：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>战略设计&lt;/strong>：划分限界上下文（Bounded Context）、定义通用语言（Ubiquitous Language）&lt;/li>
&lt;li>&lt;strong>战术设计&lt;/strong>：实体、值对象、聚合、仓储、领域服务、领域事件等构建块&lt;/li>
&lt;/ul>
&lt;p>本文聚焦&lt;strong>战术设计&lt;/strong>，以分层架构为核心，展示 DDD 如何在代码中落地。&lt;/p>
&lt;hr>
&lt;h2 id="ddd-四层架构">DDD 四层架构
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">graph TB
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef presentation fill:#e3f2fd,stroke:#1e88e5,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef application fill:#e8f5e9,stroke:#43a047,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef domain fill:#fff3e0,stroke:#fb8c00,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef infrastructure fill:#fce4ec,stroke:#d81b60,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph PL [表现层 Presentation Layer]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> REST[REST API / GraphQL]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> CLI[CLI 命令行]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> MQ_IN[消息消费者]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph AL [应用层 Application Layer]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> AppService[应用服务 Application Service]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DTO[数据传输对象 DTO]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> EventHandler[领域事件处理器]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph DL [领域层 Domain Layer ⭐ 核心]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Entity[实体 Entity]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ValueObj[值对象 Value Object]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Aggregate[聚合根 Aggregate Root]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DomainService[领域服务 Domain Service]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DomainEvent[领域事件 Domain Event]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> IRepo[仓储接口 IRepository]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph IL [基础设施层 Infrastructure Layer]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> RepoImpl[仓储实现 Repository Impl]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ORM[ORM / SQL]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> MQ_OUT[消息发布者]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Cache[缓存 Redis]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ExtAPI[外部 API 客户端]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> PL --&amp;gt; AL
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> AL --&amp;gt; DL
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> IL --&amp;gt;|实现接口| DL
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> AL --&amp;gt; IL
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class REST,CLI,MQ_IN presentation
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class AppService,DTO,EventHandler application
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Entity,ValueObj,Aggregate,DomainService,DomainEvent,IRepo domain
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class RepoImpl,ORM,MQ_OUT,Cache,ExtAPI infrastructure
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>关键约束&lt;/strong>：领域层不依赖任何其他层，是整个系统的核心。&lt;/p>
&lt;hr>
&lt;h2 id="战术设计核心概念">战术设计核心概念
&lt;/h2>&lt;h3 id="1-实体entity">1. 实体（Entity）
&lt;/h3>&lt;p>实体具有&lt;strong>唯一标识&lt;/strong>，通过 ID 区分，即使属性完全相同，两个不同 ID 的实体也是不同的对象。实体的生命周期内状态可以改变。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/model/user.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">field&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">uuid4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;用户实体 - 通过 user_id 唯一标识&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">uuid4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">utcnow&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_is_active&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">repr&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">is_active&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_is_active&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">deactivate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_is_active&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;用户已经处于停用状态&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_is_active&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">change_email&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;@&amp;#34;&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">new_email&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;无效的邮件地址: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">new_email&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">email&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">new_email&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__eq__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">object&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="nb">isinstance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user_id&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user_id&lt;/span> &lt;span class="c1"># 实体相等性基于 ID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__hash__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">hash&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="2-值对象value-object">2. 值对象（Value Object）
&lt;/h3>&lt;p>值对象&lt;strong>没有唯一标识&lt;/strong>，通过所有属性值来判断相等性，且是&lt;strong>不可变的&lt;/strong>。值对象描述&amp;quot;是什么&amp;quot;，而不是&amp;quot;是哪个&amp;quot;。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/model/money.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">decimal&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># frozen=True 确保不可变&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Money&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;金额值对象 - 金额+货币的组合&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">amount&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">currency&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">__post_init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;金额不能为负数&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;货币代码必须是 3 位（如 CNY、USD）&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Money&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;Money&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;不能将 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 与 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">other&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 相加&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">other&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">amount&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">multiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">factor&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="s2">&amp;#34;Money&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">amount&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">factor&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__str__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">currency&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">amount&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 值对象的相等性基于值，而不是内存地址&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">price1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;99.00&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">price2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;99.00&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">assert&lt;/span> &lt;span class="n">price1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">price2&lt;/span> &lt;span class="c1"># True！两个不同对象但值相同&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/model/address.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Address&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;地址值对象&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">province&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">city&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">district&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">street&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">postal_code&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">full_address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">province&lt;/span>&lt;span class="si">}{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">city&lt;/span>&lt;span class="si">}{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">district&lt;/span>&lt;span class="si">}{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">street&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="3-聚合根aggregate-root">3. 聚合根（Aggregate Root）
&lt;/h3>&lt;p>聚合是&lt;strong>一组紧密关联的对象&lt;/strong>的集合，聚合根是这个集合的入口点和守卫者。外部代码只能通过聚合根访问聚合内的对象，聚合根负责&lt;strong>维护聚合内的不变性规则（Invariants）&lt;/strong>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/model/order.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">field&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">decimal&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">uuid4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.money&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Money&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.address&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Address&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.events.order_events&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OrderConfirmedEvent&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrderCancelledEvent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderLine&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;订单行 - 聚合内的实体，只能通过 Order 操作&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantity&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unit_price&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Money&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">line_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">uuid4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">subtotal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unit_price&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">multiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quantity&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Order&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;订单聚合根 - 维护订单的所有不变性规则&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">shipping_address&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Address&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">uuid4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_lines&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">OrderLine&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">repr&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;draft&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">repr&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_domain_events&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">repr&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">utcnow&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># ---- 业务行为 ----&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">add_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">product_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">qty&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">price&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;添加订单行（聚合内的不变性：每种商品只能有一行）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">any&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_id&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">product_id&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;商品 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 已在订单中，请修改数量而非重复添加&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">qty&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;商品数量必须大于 0&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">qty&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">price&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">remove_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">product_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">l&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">l&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">l&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_id&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">product_id&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">confirm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;确认订单，触发领域事件&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s2">&amp;#34;draft&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;只有草稿状态的订单可以确认，当前: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;订单中没有商品，无法确认&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;confirmed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 发布领域事件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_domain_events&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderConfirmedEvent&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_amount&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">cancel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">reason&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;cancelled&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;shipped&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;当前状态 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 无法取消&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;cancelled&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_domain_events&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderCancelledEvent&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">reason&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">reason&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># ---- 查询属性 ----&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">total_amount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subtotal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">line&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">:]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">line&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subtotal&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">status&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_status&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">lines&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">OrderLine&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_lines&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 返回副本，防止外部修改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">pop_domain_events&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;消费领域事件（应用层负责分发）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">events&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_domain_events&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_domain_events&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">clear&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">events&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="4-仓储repository">4. 仓储（Repository）
&lt;/h3>&lt;p>仓储提供了一个&lt;strong>类似集合的接口&lt;/strong>来访问聚合根，屏蔽了底层存储细节。&lt;strong>接口定义在领域层，实现在基础设施层&lt;/strong>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/repositories/order_repository.py （领域层，只有接口）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">abc&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ABC&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IOrderRepository&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;将新订单加入仓储&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Order&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;根据 ID 获取订单，不存在返回 None&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_by_customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Order&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;获取某客户的所有订单&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">update&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;更新已有订单&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># infrastructure/repositories/sql_order_repository.py （基础设施层，具体实现）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.repositories.order_repository&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">infrastructure.orm.order_orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OrderORM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">infrastructure.mappers.order_mapper&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OrderMapper&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SqlOrderRepository&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IOrderRepository&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderMapper&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_orm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Order&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderORM&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">OrderMapper&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_domain&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">orm&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">list_by_customer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Order&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orms&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderORM&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">filter_by&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">OrderMapper&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">to_domain&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">orm&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">orms&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">update&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderORM&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">orm&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;订单 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 不存在&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">OrderMapper&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">update_orm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="5-领域服务domain-service">5. 领域服务（Domain Service）
&lt;/h3>&lt;p>当某个业务操作&lt;strong>跨越多个聚合&lt;/strong>，或者不自然地归属于某个实体时，应使用领域服务。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/services/pricing_service.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">decimal&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.money&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Money&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PricingService&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;定价领域服务：计算跨聚合的折扣规则（不属于 Order 或 Customer 单独负责）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">calculate_discount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">customer_tier&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;根据客户等级计算折扣金额&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">discount_rates&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;bronze&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0.00&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;silver&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0.05&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;gold&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0.10&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;platinum&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0.15&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">discount_rates&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customer_tier&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0.00&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">multiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rate&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">apply_coupon&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">coupon_code&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;应用优惠券（实际场景中还需查询优惠券仓储）&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fixed_coupons&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;SAVE20&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;20&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;SAVE50&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;50&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">fixed_coupons&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">coupon_code&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;0&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="6-领域事件domain-event">6. 领域事件（Domain Event）
&lt;/h3>&lt;p>领域事件表示&lt;strong>领域中发生了某件重要的事情&lt;/strong>，是聚合之间解耦通信的核心机制。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># domain/events/order_events.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.money&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Money&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">DomainEvent&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">occurred_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">__post_init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">object&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="fm">__setattr__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;occurred_at&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">utcnow&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderConfirmedEvent&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DomainEvent&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;订单确认后发布，通知库存服务、积分服务、通知服务等&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_amount&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Money&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">frozen&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderCancelledEvent&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DomainEvent&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;订单取消后发布，触发退款流程&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">reason&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="7-应用服务application-service">7. 应用服务（Application Service）
&lt;/h3>&lt;p>应用服务是&lt;strong>领域层的编排者&lt;/strong>，它不包含业务逻辑，只负责：加载聚合、调用领域方法、持久化、分发领域事件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># application/services/order_application_service.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">decimal&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Decimal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.money&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Money&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.model.address&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Address&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.repositories.order_repository&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">domain.services.pricing_service&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PricingService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">application.event_bus&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">EventBus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PlaceOrderCommand&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_tier&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">shipping_address&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coupon_code&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderApplicationService&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_repo&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">pricing_service&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PricingService&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">event_bus&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">EventBus&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_order_repo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">order_repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_pricing&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pricing_service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_event_bus&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">event_bus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">place_order&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PlaceOrderCommand&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 构建地址值对象&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">address&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Address&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">shipping_address&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 创建订单聚合根&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shipping_address&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">address&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 添加商品&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add_item&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;product_id&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qty&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;quantity&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">price&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">Money&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Decimal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;unit_price&amp;#34;&lt;/span>&lt;span class="p">])),&lt;/span> &lt;span class="s2">&amp;#34;CNY&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 应用折扣（领域服务）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">discount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_pricing&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">calculate_discount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_tier&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">coupon_code&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">coupon_discount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_pricing&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">apply_coupon&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">coupon_code&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">discount&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">discount&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">coupon_discount&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 确认订单（触发领域事件）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">confirm&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. 持久化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_order_repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. 分发领域事件（通知其他限界上下文）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">event&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pop_domain_events&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_event_bus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">publish&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">event&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="完整项目结构">完整项目结构
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span class="line">&lt;span class="cl">ecommerce/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── domain/ # 领域层（纯业务，零外部依赖）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── model/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── order.py # Order 聚合根 + OrderLine 实体
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── user.py # User 实体
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── money.py # Money 值对象
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── address.py # Address 值对象
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── repositories/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── order_repository.py # IOrderRepository 接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── user_repository.py # IUserRepository 接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── services/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── pricing_service.py # 领域服务
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── events/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── order_events.py # 领域事件定义
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── application/ # 应用层（编排，不含业务规则）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── services/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── order_application_service.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── commands/ # 命令对象（写操作）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── place_order_command.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── queries/ # 查询对象（读操作，可绕过领域层）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── get_order_query.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── event_bus.py # 领域事件总线接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── infrastructure/ # 基础设施层（技术实现）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── repositories/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── sql_order_repository.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── orm/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── order_orm.py # SQLAlchemy ORM 模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── mappers/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── order_mapper.py # 领域对象 ↔ ORM 模型映射
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── messaging/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── rabbitmq_event_bus.py # 领域事件总线实现
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── config/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── database.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── presentation/ # 表现层（HTTP / CLI / MQ）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── api/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── routers/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ │ └── order_router.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── schemas/ # Pydantic 请求/响应模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── order_schema.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── cli/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── admin_commands.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── main.py # 应用入口 + 依赖注入组装
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="ddd-核心概念速查表">DDD 核心概念速查表
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>概念&lt;/th>
&lt;th>特征&lt;/th>
&lt;th>判断标准&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>实体（Entity）&lt;/strong>&lt;/td>
&lt;td>有唯一 ID，状态可变&lt;/td>
&lt;td>问：同样属性的两个对象是&amp;quot;同一个&amp;quot;还是&amp;quot;两个&amp;quot;？如果是&amp;quot;两个&amp;quot;→ 实体&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>值对象（Value Object）&lt;/strong>&lt;/td>
&lt;td>无 ID，不可变，值相等即相等&lt;/td>
&lt;td>问：它描述的是&amp;quot;某物的特征&amp;quot;而不是&amp;quot;某物本身&amp;quot;？→ 值对象&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>聚合根（Aggregate Root）&lt;/strong>&lt;/td>
&lt;td>一组对象的唯一入口，维护不变性&lt;/td>
&lt;td>问：这组对象需要&amp;quot;整体保持一致&amp;quot;吗？→ 聚合&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>领域服务（Domain Service）&lt;/strong>&lt;/td>
&lt;td>无状态，跨聚合操作&lt;/td>
&lt;td>问：这个操作属于哪个实体？如果不属于任何实体 → 领域服务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>领域事件（Domain Event）&lt;/strong>&lt;/td>
&lt;td>不可变，描述已发生的事&lt;/td>
&lt;td>问：业务上&amp;quot;某件重要的事发生了&amp;quot;，需要通知其他系统？→ 领域事件&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>仓储（Repository）&lt;/strong>&lt;/td>
&lt;td>集合语义，只处理聚合根&lt;/td>
&lt;td>一个聚合根对应一个仓储接口&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>应用服务（Application Service）&lt;/strong>&lt;/td>
&lt;td>编排，无业务逻辑&lt;/td>
&lt;td>只调用领域对象，不写 if/else 业务判断&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="何时选择-ddd-分层架构">何时选择 DDD 分层架构？
&lt;/h2>&lt;p>&lt;strong>适合使用 DDD 的场景&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>业务规则复杂，存在大量&amp;quot;不变性约束&amp;quot;（如订单状态机）&lt;/li>
&lt;li>需要多个团队协作，需要清晰的限界上下文划分&lt;/li>
&lt;li>系统需要长期演进，希望业务逻辑不被技术细节污染&lt;/li>
&lt;li>与领域专家深度合作，需要共享通用语言&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>不适合 DDD 的场景&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>简单 CRUD 系统（用 MVC 三层就够了）&lt;/li>
&lt;li>快速原型验证，后期再演进&lt;/li>
&lt;li>团队对 DDD 概念不熟悉且没有时间学习&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="参考资料">参考资料
&lt;/h2>&lt;ul>
&lt;li>Eric Evans - &lt;em>Domain-Driven Design: Tackling Complexity in the Heart of Software&lt;/em> (2003)&lt;/li>
&lt;li>Vaughn Vernon - &lt;em>Implementing Domain-Driven Design&lt;/em> (2013)&lt;/li>
&lt;li>Vaughn Vernon - &lt;em>Domain-Driven Design Distilled&lt;/em> (2016)&lt;/li>
&lt;/ul></description></item><item><title>简洁架构（Clean Architecture）：让业务逻辑永远不依赖框架</title><link>https://www.zata.cc/p/%E7%AE%80%E6%B4%81%E6%9E%B6%E6%9E%84clean-architecture%E8%AE%A9%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%E6%B0%B8%E8%BF%9C%E4%B8%8D%E4%BE%9D%E8%B5%96%E6%A1%86%E6%9E%B6/</link><pubDate>Sun, 12 Apr 2026 11:00:00 +0800</pubDate><guid>https://www.zata.cc/p/%E7%AE%80%E6%B4%81%E6%9E%B6%E6%9E%84clean-architecture%E8%AE%A9%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%E6%B0%B8%E8%BF%9C%E4%B8%8D%E4%BE%9D%E8%B5%96%E6%A1%86%E6%9E%B6/</guid><description>&lt;h2 id="什么是简洁架构">什么是简洁架构？
&lt;/h2>&lt;p>简洁架构（Clean Architecture）由 Robert C. Martin（Uncle Bob）在 2012 年提出，它并非一个新概念，而是对&lt;strong>六边形架构&lt;/strong>、&lt;strong>洋葱架构&lt;/strong>、&lt;strong>BCE 架构&lt;/strong>等多种架构思想的统一与提炼。&lt;/p>
&lt;p>&lt;strong>核心目标只有一个&lt;/strong>：让系统中最重要的部分——&lt;strong>业务规则（Business Rules）&lt;/strong>——与框架、数据库、UI 完全解耦，使其可以独立测试、独立替换。&lt;/p>
&lt;hr>
&lt;h2 id="同心圆模型">同心圆模型
&lt;/h2>&lt;p>简洁架构的标志性图示是四个同心圆，从内到外依次是：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl"> ┌─────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ Frameworks &amp;amp; Drivers │ ← 最外层：Web框架、DB、UI
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ ┌─────────────────────────────────┐ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ Interface Adapters │ │ ← 控制器、网关、Presenter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ ┌─────────────────────────┐ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ Application Business │ │ │ ← Use Cases（用例）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ Rules │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ ┌─────────────────┐ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ │ Enterprise │ │ │ │ ← Entities（实体/领域对象）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ │ Business Rules │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ └─────────────────┘ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ └─────────────────────────┘ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ └─────────────────────────────────┘ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └─────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">graph LR
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef entity fill:#e8f5e9,stroke:#43a047,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef usecase fill:#e3f2fd,stroke:#1e88e5,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef adapter fill:#fff3e0,stroke:#fb8c00,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef framework fill:#fce4ec,stroke:#d81b60,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph L4 [Frameworks &amp;amp; Drivers]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> FastAPI[FastAPI / Flask]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> MySQL[(MySQL / PostgreSQL)]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Redis[(Redis)]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph L3 [Interface Adapters]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Controller[Controller 控制器]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Presenter[Presenter 输出格式化]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Gateway[Repository Gateway]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph L2 [Application Business Rules]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC1[UseCase: CreateOrder]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC2[UseCase: CancelOrder]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC3[UseCase: QueryOrder]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph L1 [Enterprise Business Rules]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Order[Order 实体]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> OrderItem[OrderItem 值对象]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> IOrderRepo[IOrderRepository 接口]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> FastAPI --&amp;gt; Controller
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Controller --&amp;gt; UC1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC1 --&amp;gt; Order
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC1 --&amp;gt; IOrderRepo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Gateway --&amp;gt;|实现| IOrderRepo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> MySQL --&amp;gt; Gateway
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Order,OrderItem,IOrderRepo entity
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class UC1,UC2,UC3 usecase
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Controller,Presenter,Gateway adapter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class FastAPI,MySQL,Redis framework
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="核心原则依赖规则the-dependency-rule">核心原则：依赖规则（The Dependency Rule）
&lt;/h2>&lt;blockquote>
&lt;p>&lt;strong>源代码依赖只能从外向内指向。内层对外层一无所知。&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>这条规则是简洁架构的灵魂：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>层级&lt;/th>
&lt;th>可以依赖&lt;/th>
&lt;th>不可以依赖&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Entities（实体）&lt;/td>
&lt;td>无任何外部依赖&lt;/td>
&lt;td>全部外层&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Use Cases（用例）&lt;/td>
&lt;td>Entities&lt;/td>
&lt;td>Adapters、Frameworks&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Adapters（适配器）&lt;/td>
&lt;td>Use Cases、Entities&lt;/td>
&lt;td>Frameworks（直接耦合）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Frameworks（框架）&lt;/td>
&lt;td>全部内层&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>实际含义举例&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;code>Order&lt;/code> 实体类里，不能出现 &lt;code>import sqlalchemy&lt;/code>&lt;/li>
&lt;li>&lt;code>CreateOrderUseCase&lt;/code> 里，不能出现 &lt;code>import fastapi&lt;/code>&lt;/li>
&lt;li>数据库从 MySQL 换成 MongoDB，只需修改最外层的 Repository 实现，业务逻辑零改动&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="四层详解">四层详解
&lt;/h2>&lt;h3 id="第一层entities企业业务规则">第一层：Entities（企业业务规则）
&lt;/h3>&lt;p>实体封装了最核心、最稳定的业务规则，它们与任何应用无关，只表达&amp;quot;这个领域的事物是什么&amp;quot;。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># entities/order.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">field&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datetime&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">enum&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Enum&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">uuid4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderStatus&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Enum&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PENDING&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;pending&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CONFIRMED&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;confirmed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CANCELLED&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;cancelled&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OrderItem&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantity&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unit_price&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">subtotal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quantity&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unit_price&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Order&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">OrderItem&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">list&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">uuid4&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">OrderStatus&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PENDING&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">datetime&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">field&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">default_factory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">utcnow&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@property&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">total_amount&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">sum&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">subtotal&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">confirm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PENDING&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;只有 PENDING 状态的订单才能确认，当前状态: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CONFIRMED&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">cancel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CANCELLED&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;订单已经取消&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">CANCELLED&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>注意&lt;/strong>：这里没有任何 &lt;code>import&lt;/code> 涉及框架或数据库。实体是纯 Python 对象，可以独立测试。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h3 id="第二层use-cases应用业务规则">第二层：Use Cases（应用业务规则）
&lt;/h3>&lt;p>用例编排实体的业务行为，代表&amp;quot;系统能做什么&amp;quot;。它通过**接口（抽象）**与外部世界交互，而不直接依赖具体实现。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># use_cases/interfaces.py （定义抽象接口，属于内层）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">abc&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ABC&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">entities.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IOrderRepository&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">find_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Order&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">IPaymentGateway&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">charge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">amount&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">bool&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">INotificationService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">send_confirmation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># use_cases/create_order.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dataclasses&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">entities.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrderItem&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">use_cases.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">IPaymentGateway&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INotificationService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CreateOrderRequest&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># [{product_id, product_name, quantity, unit_price}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@dataclass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CreateOrderResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_amount&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CreateOrderUseCase&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_repo&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">payment_gateway&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">IPaymentGateway&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">notification_service&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">INotificationService&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_order_repo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">order_repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_payment&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">payment_gateway&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_notification&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">notification_service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">CreateOrderRequest&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">CreateOrderResponse&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 创建领域对象&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item_data&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderItem&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">item_data&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 执行支付（通过接口，不关心底层是支付宝还是微信）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">success&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_payment&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">charge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">success&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;支付失败，请检查账户余额&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 确认订单（领域规则在实体内部）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">confirm&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 持久化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_order_repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 发送通知&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_notification&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_confirmation&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">CreateOrderResponse&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">total_amount&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="第三层interface-adapters接口适配器">第三层：Interface Adapters（接口适配器）
&lt;/h3>&lt;p>这一层负责在&amp;quot;用例的数据格式&amp;quot;和&amp;quot;外部世界的数据格式&amp;quot;之间做转换。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># adapters/repositories/sql_order_repository.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">entities.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrderItem&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrderStatus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">use_cases.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">IOrderRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.models&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OrderORM&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">OrderItemORM&lt;/span> &lt;span class="c1"># ORM 模型定义在此层&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">SqlOrderRepository&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IOrderRepository&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;将 IOrderRepository 接口适配到 SQLAlchemy 实现&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderORM&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">status&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">created_at&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">created_at&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderItemORM&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quantity&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unit_price&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unit_price&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">find_by_id&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">order_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Order&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">orm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderORM&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">orm&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_orm_to_entity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">_orm_to_entity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">orm&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">OrderORM&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Order&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">UUID&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">UUID&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OrderStatus&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">created_at&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">created_at&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item_orm&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">OrderItem&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">UUID&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item_orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">product_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item_orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">product_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item_orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">quantity&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">unit_price&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">item_orm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">unit_price&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">order&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># adapters/controllers/order_controller.py （FastAPI 路由层）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">APIRouter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Depends&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pydantic&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BaseModel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">use_cases.create_order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CreateOrderRequest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.dependencies&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">get_create_order_use_case&lt;/span> &lt;span class="c1"># 依赖注入工厂&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">router&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">APIRouter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prefix&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/orders&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tags&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;orders&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">CreateOrderHTTPRequest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseModel&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">UUID&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">dict&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@router.post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">status_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">201&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">create_order&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">body&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">CreateOrderHTTPRequest&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_case&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Depends&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">get_create_order_use_case&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CreateOrderRequest&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">customer_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">use_case&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;order_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">order_id&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s2">&amp;#34;total&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="第四层frameworks--drivers框架与驱动">第四层：Frameworks &amp;amp; Drivers（框架与驱动）
&lt;/h3>&lt;p>最外层是所有技术细节：Web 框架、ORM、消息队列、缓存。这层的代码量最少，主要是&amp;quot;组装&amp;quot;，而非&amp;quot;业务&amp;quot;。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># main.py （应用入口，负责依赖组装）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">FastAPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">create_engine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">sessionmaker&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.controllers.order_controller&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">router&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.repositories.sql_order_repository&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SqlOrderRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.gateways.stripe_payment_gateway&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">StripePaymentGateway&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">adapters.services.email_notification_service&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">EmailNotificationService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">use_cases.create_order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">FastAPI&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">include_router&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">router&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">engine&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">create_engine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;postgresql://user:pass@localhost/orders_db&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SessionLocal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sessionmaker&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bind&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">engine&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 依赖注入：在此处将接口绑定到具体实现&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_create_order_use_case&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SessionLocal&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">order_repo&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SqlOrderRepository&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">session&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">payment_gateway&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">StripePaymentGateway&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;sk_live_...&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">notification_service&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">EmailNotificationService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smtp_host&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;smtp.example.com&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="项目目录结构">项目目录结构
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span class="line">&lt;span class="cl">my_app/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── entities/ # 第一层：纯领域对象，零外部依赖
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── order.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── user.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── use_cases/ # 第二层：业务用例 + 接口定义
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── interfaces.py # 抽象接口（Repository, Gateway 等）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── create_order.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── cancel_order.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── adapters/ # 第三层：格式转换和具体实现
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── controllers/ # HTTP 控制器（FastAPI/Flask 路由）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── repositories/ # Repository 具体实现（SQL/MongoDB）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── gateways/ # 第三方服务网关（支付、短信等）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── services/ # 其他服务实现（通知、缓存等）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── models.py # ORM 模型定义
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── frameworks/ # 第四层：框架配置、应用组装
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── dependencies.py # 依赖注入工厂函数
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── unit/ # 单元测试：只测 entities 和 use_cases
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── integration/ # 集成测试：测 adapters 层
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── main.py # 应用入口
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="如何测试">如何测试？
&lt;/h2>&lt;p>简洁架构最大的优势就是&lt;strong>可测性&lt;/strong>。用例层可以通过 Mock 接口进行纯单元测试，无需启动数据库或 HTTP 服务：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># tests/unit/test_create_order.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">unittest.mock&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">MagicMock&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">uuid&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">uuid4&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">entities.order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Order&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">use_cases.create_order&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CreateOrderRequest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_create_order_success&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Arrange：Mock 所有外部依赖&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_repo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MagicMock&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_payment&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MagicMock&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_payment&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">charge&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">return_value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># 支付成功&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_notification&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">MagicMock&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_case&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CreateOrderUseCase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mock_repo&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mock_payment&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mock_notification&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CreateOrderRequest&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">customer_id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">uuid4&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;product_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">uuid4&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;product_name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Python 编程书&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;quantity&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;unit_price&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">89.0&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Act&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">use_case&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Assert：不依赖数据库，测试飞快&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">total_amount&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mf">178.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;confirmed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assert_called_once&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_notification&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_confirmation&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assert_called_once&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="简洁架构-vs-传统三层架构">简洁架构 vs 传统三层架构
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>对比维度&lt;/th>
&lt;th>传统三层（Controller → Service → DAO）&lt;/th>
&lt;th>简洁架构&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>依赖方向&lt;/strong>&lt;/td>
&lt;td>从上往下，Service 依赖 DAO&lt;/td>
&lt;td>向内收敛，业务不依赖技术&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>可测性&lt;/strong>&lt;/td>
&lt;td>Service 难以脱离数据库测试&lt;/td>
&lt;td>Use Case 可纯 Mock 测试&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>替换框架&lt;/strong>&lt;/td>
&lt;td>换 ORM 需改 Service 层&lt;/td>
&lt;td>只改最外层 Repository 实现&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>业务清晰度&lt;/strong>&lt;/td>
&lt;td>业务逻辑散落在 Service 和 DAO 之间&lt;/td>
&lt;td>业务逻辑集中在 Entity + Use Case&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>学习成本&lt;/strong>&lt;/td>
&lt;td>低，上手快&lt;/td>
&lt;td>中等，需要理解接口抽象&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>适用规模&lt;/strong>&lt;/td>
&lt;td>小型项目、CRUD 为主&lt;/td>
&lt;td>中大型、业务复杂、长期维护&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="常见误区">常见误区
&lt;/h2>&lt;p>&lt;strong>误区 1：实体（Entity）= 数据库表&lt;/strong>&lt;/p>
&lt;p>在简洁架构中，Entity 是&lt;strong>领域对象&lt;/strong>，包含业务规则和行为，不是数据库行的映射。数据库 ORM 模型应放在 Adapters 层。&lt;/p>
&lt;p>&lt;strong>误区 2：每个项目都要用简洁架构&lt;/strong>&lt;/p>
&lt;p>对于简单的 CRUD 项目，简洁架构反而是过度设计。当业务规则复杂、团队较大、需要长期维护时，它的价值才能充分体现。&lt;/p>
&lt;p>&lt;strong>误区 3：必须严格分四层&lt;/strong>&lt;/p>
&lt;p>层数可以根据项目规模调整。小项目可以合并 Entities + Use Cases 为一个 &lt;code>domain/&lt;/code> 目录，重要的是&lt;strong>依赖方向的原则&lt;/strong>不能违背。&lt;/p>
&lt;hr>
&lt;h2 id="参考资料">参考资料
&lt;/h2>&lt;ul>
&lt;li>Robert C. Martin - &lt;em>Clean Architecture: A Craftsman&amp;rsquo;s Guide to Software Structure and Design&lt;/em> (2017)&lt;/li>
&lt;li>&lt;a class="link" href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" target="_blank" rel="noopener"
>The Clean Architecture - Uncle Bob&amp;rsquo;s Blog&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>从脚本到企业级平台：AI Agent 系统"整洁架构"演进与 Python 落地指南</title><link>https://www.zata.cc/p/ai-agent-clean-architecture/</link><pubDate>Sun, 12 Apr 2026 10:00:00 +0800</pubDate><guid>https://www.zata.cc/p/ai-agent-clean-architecture/</guid><description>&lt;p>在 AI 应用爆发的今天，写一个大模型对话脚本只需要 50 行代码。但如果你要开发一个企业级的 Agent 管理平台（支持复杂任务编排、多模型无缝切换、RAG 知识库、数十种动态拔插的 Skill 工具），那 50 行脚本很快就会演变成无法维护的&amp;quot;屎山代码&amp;quot;。&lt;/p>
&lt;p>&lt;strong>痛点极其明显：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>大模型 API 换了（比如从 OpenAI 换到 DeepSeek），整个系统要大改。&lt;/li>
&lt;li>加一个新工具（Skill），由于和核心逻辑严重耦合，不小心把之前的流式输出改崩了。&lt;/li>
&lt;li>系统无法进行单元测试，每次测试都得真金白银地消耗 Token。&lt;/li>
&lt;/ul>
&lt;p>为了解决这些问题，结合&lt;strong>领域驱动设计 (DDD)&lt;/strong> 和 Uncle Bob 的&lt;strong>整洁架构 (Clean Architecture)&lt;/strong> 原则，我们设计了一套**&amp;ldquo;四层模块化单体架构&amp;rdquo;**。&lt;/p>
&lt;p>本文将通过深度图解与真实代码，带你一步步落地这个现代 Agent 平台架构。&lt;/p>
&lt;hr>
&lt;h2 id="一架构蓝图agent-的数字仿生体">一、架构蓝图：Agent 的&amp;quot;数字仿生体&amp;quot;
&lt;/h2>&lt;p>我们不把系统看作一堆代码的集合，而是将它隐喻为一个**&amp;ldquo;数字员工&amp;rdquo;**。以下是系统的全局架构图：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">graph TD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef appLayer fill:#e3f2fd,stroke:#1e88e5,stroke-width:2px,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef coreLayer fill:#e8f5e9,stroke:#43a047,stroke-width:2px,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef platLayer fill:#fff3e0,stroke:#fb8c00,stroke-width:2px,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef infraLayer fill:#fce4ec,stroke:#d81b60,stroke-width:2px,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> classDef external fill:#f5f5f5,stroke:#9e9e9e,stroke-width:2px,stroke-dasharray: 5 5,color:#000
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> User([用户 / 前端 / 定时器]) --&amp;gt; API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph Layer1 [1. Apps 层: 感官与嘴巴 - 负责请求接入]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> API[api/ RESTful Web API]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> WS[websocket/ 流式对话]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph Layer2 [2. Core 层: 核心大脑 - 绝对纯洁的业务逻辑]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC[use_cases/ 业务编排: execute_task]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph AgentCore [agent/ 思考与推理]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Orchestrator[orchestrator.py 调度引擎]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Planner[planner.py ReAct/CoT 算法]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Memory[memory.py 记忆摘要]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Interfaces((shared/interfaces 接口定义))
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph Layer3 [3. Platform 层: 躯干与技能 - 插件化生态]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Registry[skills/registry.py 技能注册表]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> SkillBase[skills/base.py 技能基类]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> WeatherSkill[skills/weather_skill.py]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> RAG[rag/ 知识检索与切片]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph Layer4 [4. Infrastructure 层: 物理世界驱动]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> LLM[models/ OpenAI/Qwen 客户端]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DB[persistence/ MySQL/Redis]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> HTTP[http_clients/ 发请求查天气等]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> subgraph External [外部物理世界]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ExtLLM[大模型 API]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ExtWeather[第三方天气 API]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ExtDB[(物理数据库)]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> end
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> API --&amp;gt; UC
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> WS --&amp;gt; UC
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> UC --&amp;gt; Orchestrator
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Orchestrator --&amp;gt; Planner
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Orchestrator --&amp;gt; Memory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Orchestrator -.-&amp;gt; |定义标准| Interfaces
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Registry -.-&amp;gt; |实现| Interfaces
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> SkillBase -.-&amp;gt; |实现| Interfaces
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> WeatherSkill --&amp;gt; HTTP
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> RAG --&amp;gt; DB
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> LLM -.-&amp;gt; |实现| Interfaces
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DB -.-&amp;gt; |实现| Interfaces
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> LLM ==&amp;gt; ExtLLM
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> HTTP ==&amp;gt; ExtWeather
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> DB ==&amp;gt; ExtDB
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Layer1,API,WS appLayer;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Layer2,UC,AgentCore,Orchestrator,Planner,Memory,Interfaces coreLayer;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Layer3,Registry,SkillBase,WeatherSkill,RAG platLayer;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class Layer4,LLM,DB,HTTP infraLayer;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> class External,ExtLLM,ExtWeather,ExtDB external;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>项目目录结构（与四层架构严格对应）：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">agent-platform/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── frontend/ # [独立] 前端层：四层架构的消费者，与后端并列存在
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── pages/ # 页面（对话页、任务历史、技能管理）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── components/ # UI 组件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── api/ # 封装对 apps/ 层的 HTTP/WebSocket 调用
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── package.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── apps/ # [第1层] Apps 层：请求接入，最薄的一层
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── api/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── router.py # FastAPI 路由，只做参数校验和调用用例
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── schemas.py # 请求/响应 Pydantic 模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── websocket/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── handler.py # WebSocket 流式对话处理器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── core/ # [第2层] Core 层：纯洁的业务大脑，禁止导入外部库
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── agent/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── orchestrator.py # Agent 编排引擎，驱动 ReAct 循环
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── planner.py # 思考算法（ReAct / CoT / ToT）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── memory.py # 对话记忆与摘要压缩
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── use_cases/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── execute_task.py # 业务用例入口：接收请求，返回结果
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── shared/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── interfaces.py # 🔑 核心契约：ILLMInterface / ISkill / ISkillRegistry
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── platform/ # [第3层] Platform 层：插件生态，实现 Core 的接口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── skills/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── base.py # 技能基类（对 ISkill 的便捷封装）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── registry.py # 技能注册表（实现 ISkillRegistry）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── weather_skill.py # 天气查询技能
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── email_skill.py # 发邮件技能（未来扩展）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── code_skill.py # 代码执行技能（未来扩展）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── rag/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── retriever.py # 向量检索
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── chunker.py # 文本切片
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── infrastructure/ # [第4层] Infrastructure 层：脏活累活，对接物理世界
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── models/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── openai_client.py # OpenAI 实现（实现 ILLMInterface）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── deepseek_client.py # DeepSeek 实现（未来扩展，换这里即可）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── persistence/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── mysql_repo.py # MySQL 数据访问
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── redis_cache.py # Redis 缓存
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── http_clients/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── weather_api.py # 第三方天气 API 封装
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── tests/ # 测试目录（Core 层可纯 Mock 测试，无需消耗 Token）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── unit/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── test_orchestrator.py # 单元测试：Mock LLM 和 Skill
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── integration/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── test_weather_flow.py # 集成测试：端到端流程
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── main.py # 依赖注入组装入口：将四层粘合成完整系统
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>架构四大层级剖析（依赖箭头永远向内或靠接口反转）：&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>层级&lt;/th>
&lt;th>职责&lt;/th>
&lt;th>禁止事项&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Frontend（前端，独立）&lt;/strong>&lt;/td>
&lt;td>渲染 UI、发起 HTTP/WebSocket 请求，只与 Apps 层通信&lt;/td>
&lt;td>不得直接调用 Core 或 Platform 的任何逻辑&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Apps（请求接入层）&lt;/strong>&lt;/td>
&lt;td>接收 HTTP/WebSocket 请求，参数校验，转发给 Core&lt;/td>
&lt;td>不得包含业务逻辑&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Core（核心大脑层）&lt;/strong>&lt;/td>
&lt;td>Agent 思考逻辑（ReAct 循环）、业务编排&lt;/td>
&lt;td>禁止 &lt;code>import requests&lt;/code> 或任何外部库&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Platform（平台服务层）&lt;/strong>&lt;/td>
&lt;td>技能市场、RAG 知识库，动态注册 Skill&lt;/td>
&lt;td>不得直接访问物理数据库&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Infrastructure（基础设施层）&lt;/strong>&lt;/td>
&lt;td>调用 OpenAI SDK、查 MySQL、读文件等脏活&lt;/td>
&lt;td>不得包含业务逻辑&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>前端的角色定位：&lt;/strong> &lt;code>frontend/&lt;/code> 是整个系统的&amp;quot;嘴脸&amp;quot;，但它不属于后端四层中的任何一层。它是架构的&lt;strong>消费者&lt;/strong>，只能通过 &lt;code>apps/&lt;/code> 层暴露的 API/WebSocket 接口与系统交互，对 &lt;code>core/&lt;/code>、&lt;code>platform/&lt;/code>、&lt;code>infrastructure/&lt;/code> 的存在一无所知。如果项目规模扩大，前端可以直接拆分为独立仓库单独部署，后端四层结构无需任何改动。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="二代码级穿越以帮我查一下杭州明天天气为例">二、代码级穿越：以&amp;quot;帮我查一下杭州明天天气&amp;quot;为例
&lt;/h2>&lt;p>接下来，严格按照目录结构，用 Python 代码走通一笔真实业务流，体会依赖倒置带来的窒息级优雅。&lt;/p>
&lt;h3 id="1-定义防腐接口-coresharedinterfacespy">1. 定义防腐接口 &lt;code>core/shared/interfaces.py&lt;/code>
&lt;/h3>&lt;p>这是整个系统架构的&amp;quot;契约&amp;quot;，Core 层需要的工具箱全在这里定义。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># core/shared/interfaces.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">abc&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ABC&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Dict&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Any&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ILLMInterface&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;大模型提供商的抽象接口&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">generate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ISkill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;所有平台技能的抽象基类&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">kwargs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Any&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">ISkillRegistry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ABC&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;技能注册表的抽象接口&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_skill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ISkill&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@abstractmethod&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_all_schemas&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">pass&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-编写核心大脑-coreagentorchestratorpy">2. 编写核心大脑 &lt;code>core/agent/orchestrator.py&lt;/code>
&lt;/h3>&lt;p>这里是 Agent 的思考流，它&lt;strong>只依赖刚才定义的接口&lt;/strong>，与任何具体实现完全解耦。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># core/agent/orchestrator.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.shared.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ILLMInterface&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ISkillRegistry&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AgentOrchestrator&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Agent 编排引擎 (纯业务逻辑)&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 依赖注入：在初始化时，只接收接口，不知道底层是谁&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">llm&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ILLMInterface&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">skill_registry&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">ISkillRegistry&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llm&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">skill_registry&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">skill_registry&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_query&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;[Core] 收到任务: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. 获取系统目前所有可用的技能说明书&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">available_tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">skill_registry&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_all_schemas&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. 让 LLM 思考意图&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;[Core] 正在调用大脑(LLM)分析意图...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm_response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user_query&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tools&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">available_tools&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. 解析 LLM 返回结果，判断是否需要调用工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">llm_response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;tool_call&amp;#34;&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llm_response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tool_call&amp;#34;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tool_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llm_response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;tool_call&amp;#34;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="s2">&amp;#34;args&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;[Core] 大脑决定调用技能: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tool_name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, 参数: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">tool_args&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. 去平台层获取具体技能并执行&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">skill&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">skill_registry&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_skill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">tool_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">observation&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">skill&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">**&lt;/span>&lt;span class="n">tool_args&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;[Core] 技能执行结果: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">observation&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. 拿着结果进行二次总结&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">final_prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;用户问:&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">user_query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">工具返回:&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">observation&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">请给出最终人类可读回答。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">final_answer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">final_prompt&lt;/span>&lt;span class="p">)[&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">final_answer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">llm_response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># core/use_cases/execute_task.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.agent.orchestrator&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AgentOrchestrator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">execute_chat_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">orchestrator&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">AgentOrchestrator&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;业务用例：执行对话任务&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">orchestrator&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-构建平台生态与技能-platformskills">3. 构建平台生态与技能 &lt;code>platform/skills/&lt;/code>
&lt;/h3>&lt;p>跳出核心大脑，来到 platform 层，实现具体的技能插件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># platform/skills/weather_skill.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.shared.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ISkill&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span> &lt;span class="c1"># Platform/Infra 层允许导入外部库&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">WeatherSkill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ISkill&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;weather_skill&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">description&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;查询指定城市的天气。参数包含 city: 城市名&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">city&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;[Platform] 正在查询物理世界 &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">city&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> 的天气...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 模拟调用外部 HTTP API (严格来说 HTTP 调用也可抽离到 infra 层)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># response = requests.get(f&amp;#34;http://weather-api.com?city={city}&amp;#34;)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">city&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">明天晴，25摄氏度，适合出行。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># platform/skills/registry.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.shared.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ISkillRegistry&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ISkill&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">platform.skills.weather_skill&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">WeatherSkill&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LocalSkillRegistry&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ISkillRegistry&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;技能注册表的具体实现&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_skills&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;weather_skill&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">WeatherSkill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 未来可以在这里无缝插入 code_skill, search_skill&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_skill&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">ISkill&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_skills&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">get_all_schemas&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;description&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">description&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">s&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_skills&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">values&lt;/span>&lt;span class="p">()]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-接入基础设施-infrastructuremodels">4. 接入基础设施 &lt;code>infrastructure/models/&lt;/code>
&lt;/h3>&lt;p>老板要求这次用 OpenAI 实现大脑。我们去 infra 搬砖。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># infrastructure/models/openai_client.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.shared.interfaces&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ILLMInterface&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Dict&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">OpenAIClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ILLMInterface&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;大模型接口的具体实现&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="fm">__init__&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_key&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="bp">self&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># openai.api_key = api_key&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">generate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tools&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">Dict&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">Dict&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 这里模拟 OpenAI Function Calling 的真实返回结构&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="s2">&amp;#34;天气&amp;#34;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;tool_call&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;weather_skill&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;args&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;city&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;杭州&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;这是一个普通的聊天回复&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="5-大一统应用入口与依赖注入-mainpy">5. 大一统：应用入口与依赖注入 &lt;code>main.py&lt;/code>
&lt;/h3>&lt;p>这是最外层的框架代码，将灵魂、躯干、基础设施组装成一个完整的生命体。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># main.py (或 apps/api/router.py)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.agent.orchestrator&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AgentOrchestrator&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">core.use_cases.execute_task&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">execute_chat_task&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">platform.skills.registry&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LocalSkillRegistry&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">infrastructure.models.openai_client&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">OpenAIClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ==========================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 依赖注入 (DI) - 组装数字人&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 如果明天换成 Qwen 模型，只需改下面这一行，其他代码一行不动！&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ==========================================&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">llm_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">OpenAIClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;sk-xxxx&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">skill_registry&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LocalSkillRegistry&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 将外部躯干注入到大脑中&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">orchestrator&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AgentOrchestrator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm_client&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">skill_registry&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">skill_registry&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">mock_websocket_request&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user_input&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;帮我查一下杭州明天的天气&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- 请求开始 ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Apps 层将请求交给 Core 层的用例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">final_result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">execute_chat_task&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user_input&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">orchestrator&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;--- 最终输出给用户 ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">final_result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mock_websocket_request&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="三终端运行效果日志穿透层级">三、终端运行效果（日志穿透层级）
&lt;/h2>&lt;p>运行 &lt;code>main.py&lt;/code>，你将清晰地看到请求是如何穿透这四个架构层的：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">--- 请求开始 ---
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[Core] 收到任务: 帮我查一下杭州明天的天气
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[Core] 正在调用大脑(LLM)分析意图...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[Core] 大脑决定调用技能: weather_skill, 参数: {&amp;#39;city&amp;#39;: &amp;#39;杭州&amp;#39;}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[Platform] 正在查询物理世界 杭州 的天气...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">[Core] 技能执行结果: 杭州明天晴，25摄氏度，适合出行。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">--- 最终输出给用户 ---
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">用户问:帮我查一下杭州明天的天气
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">工具返回:杭州明天晴，25摄氏度，适合出行。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">请给出最终人类可读回答。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="四为什么一定要这样设计灵魂三问">四、为什么一定要这样设计？（灵魂三问）
&lt;/h2>&lt;h3 id="1-platform-扩展的威力">1. Platform 扩展的威力
&lt;/h3>&lt;p>仔细看 &lt;code>platform/skills/&lt;/code> 目录。这就是你系统的&amp;quot;外挂市场&amp;quot;。当业务需要增加一个&amp;quot;一键发送邮件&amp;quot;的功能时：&lt;/p>
&lt;blockquote>
&lt;p>你只需要写一个 &lt;code>email_skill.py&lt;/code>，实现 &lt;code>ISkill&lt;/code> 接口，然后在 &lt;code>registry.py&lt;/code> 里注册即可。系统的核心大脑（Core）完全不需要重构，它甚至不需要重新启动，就能在下一次请求中知道并使用这个新工具。&lt;/p>
&lt;/blockquote>
&lt;p>如果配合最新的 MCP (Model Context Protocol)，你甚至可以动态加载全网的开源工具。&lt;/p>
&lt;h3 id="2-抵御大模型迭代的降维打击">2. 抵御大模型迭代的降维打击
&lt;/h3>&lt;p>今天 OpenAI 是最强的，明天 DeepSeek 放出了更便宜更好的模型。在面条代码里，这意味着重写几千行的 Prompt 和调用逻辑。&lt;/p>
&lt;p>在这个架构里，你只需要：&lt;/p>
&lt;ol>
&lt;li>在 &lt;code>infrastructure/models/&lt;/code> 建一个 &lt;code>deepseek_client.py&lt;/code>，实现 &lt;code>ILLMInterface&lt;/code>&lt;/li>
&lt;li>在 &lt;code>main.py&lt;/code> 里换一行依赖注入&lt;/li>
&lt;/ol>
&lt;p>你的核心 Agent 推理逻辑毫发无损。&lt;/p>
&lt;h3 id="3-坚守整洁生命线">3. 坚守&amp;quot;整洁&amp;quot;生命线
&lt;/h3>&lt;p>在代码审查（Code Review）时，团队必须立下一条死规矩：&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>绝对不允许 &lt;code>core/&lt;/code> 目录下的任何文件，直接 &lt;code>import platform/&lt;/code> 或 &lt;code>infrastructure/&lt;/code> 目录下的代码。&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>Core 是系统的心脏，必须保持纯净。这条规矩可以通过 &lt;code>pylint&lt;/code>、&lt;code>import-linter&lt;/code> 等工具强制执行。&lt;/p>
&lt;hr>
&lt;h2 id="结语">结语
&lt;/h2>&lt;p>模块化单体结合整洁架构，是目前应对复杂 AI 业务的最佳实践。它既避免了微服务（Microservices）早期带来的分布式运维灾难，又保持了代码的极度解耦。&lt;/p>
&lt;p>这不仅是代码结构的胜利，更是软件工程艺术的胜利。&lt;/p></description></item><item><title>FastAPI 后端架构设计</title><link>https://www.zata.cc/p/fastapi-%E5%90%8E%E7%AB%AF%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</link><pubDate>Tue, 16 Sep 2025 14:48:04 +0800</pubDate><guid>https://www.zata.cc/p/fastapi-%E5%90%8E%E7%AB%AF%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/</guid><description>&lt;img src="https://www.zata.cc/p/fastapi-%E5%90%8E%E7%AB%AF%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/images/index/index.png" alt="Featured image of post FastAPI 后端架构设计" />&lt;h1 id="fastapi-项目结构化教程">FastAPI 项目结构化教程
&lt;/h1>&lt;p>这是一个经过精心设计的、适用于中大型项目的 FastAPI 后端目录结构。它具有良好的模块化、可扩展性和可维护性。&lt;/p>
&lt;h2 id="目录结构总览">目录结构总览
&lt;/h2>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-gdscript3" data-lang="gdscript3">&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">app&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 主要的应用代码目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 将 app 目录标记为 Python 包&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">main&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># FastAPI 应用的入口文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">api&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># API 路由（endpoints）层&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">v1&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># API 版本 v1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">api&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 聚合 v1 版本的所有路由&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">endpoints&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 存放各个模块的路由文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">core&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 核心逻辑与配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 应用配置（环境变量等）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">security&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 安全相关（密码哈希、JWT令牌等）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 日志配置与工具&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│──&lt;/span> &lt;span class="n">services&lt;/span>&lt;span class="o">/&lt;/span> &lt;span class="c1"># 新增: 业务逻辑层 (工作流)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">__init__&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">chat_agent&lt;/span>&lt;span class="o">/&lt;/span> &lt;span class="c1"># 例如 （LangGraph Agent）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">__init__&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">graph&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> &lt;span class="c1"># 编译后的 Agent (Workflow)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">state&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> &lt;span class="c1"># AgentState&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">nodes&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> &lt;span class="c1"># 节点函数&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">tools&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> &lt;span class="c1"># 工具 (e.g., RAG, DB lookup)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">crud&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># CRUD 数据库操作层&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 可复用的 CRUD 基类&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">crud&lt;/span>\&lt;span class="n">_user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 针对 User 模型的 CRUD 操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">crud&lt;/span>\&lt;span class="n">_item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 针对 Item 模型的 CRUD 操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 数据库相关&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># SQLAlchemy 的声明式基类 (DeclarativeBase)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">session&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 数据库会话管理&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">init&lt;/span>\&lt;span class="n">_db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># (可选) 初始化数据库脚本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">models&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># SQLAlchemy ORM 模型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">schemas&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># Pydantic 数据模型（用于数据校验与序列化）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># FastAPI 依赖项注入&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">common&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># 通用依赖项（如获取DB会话、获取当前用户）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">tests&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 测试代码目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="o">**&lt;/span>&lt;span class="n">init&lt;/span>&lt;span class="o">**.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">conftest&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span> \&lt;span class="c1"># Pytest 的 fixtures 和配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">api&lt;/span>&lt;span class="o">/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">v1&lt;/span>&lt;span class="o">/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">test&lt;/span>\&lt;span class="n">_users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">logs&lt;/span>&lt;span class="o">/&lt;/span> \&lt;span class="c1"># 日志文件目录 (运行时自动创建)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span> \&lt;span class="c1"># 应用主日志文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">├──&lt;/span> &lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="mi">1&lt;/span> \&lt;span class="c1"># 轮转的历史日志文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span> &lt;span class="err">└──&lt;/span> &lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">log&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="mi">2&lt;/span> \&lt;span class="c1"># 轮转的历史日志文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">│&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="o">.&lt;/span>&lt;span class="n">env&lt;/span> \&lt;span class="c1"># 环境变量文件 (不应提交到 git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="o">.&lt;/span>&lt;span class="n">gitignore&lt;/span> \&lt;span class="c1"># Git 忽略文件配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">Dockerfile&lt;/span> \&lt;span class="c1"># Docker 配置文件&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">├──&lt;/span> &lt;span class="n">requirements&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">txt&lt;/span> \&lt;span class="c1"># Python 依赖包列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">└──&lt;/span> &lt;span class="n">README&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">md&lt;/span> \&lt;span class="c1"># 项目说明文档&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h2 id="详细说明">详细说明
&lt;/h2>&lt;h3 id="根目录文件">根目录文件
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>&lt;code>.env&lt;/code>&lt;/strong>: 存储敏感信息和环境变量，例如数据库连接字符串、JWT 密钥等。&lt;/li>
&lt;li>&lt;strong>&lt;code>.gitignore&lt;/code>&lt;/strong>: 定义了哪些文件或目录不应被 Git 跟踪。&lt;/li>
&lt;li>&lt;strong>&lt;code>Dockerfile&lt;/code>&lt;/strong>: 用于构建应用的 Docker 镜像，方便容器化部署。&lt;/li>
&lt;li>&lt;strong>&lt;code>requirements.txt&lt;/code>&lt;/strong>: 列出项目的所有 Python 依赖库，使用 &lt;code>pip install -r requirements.txt&lt;/code> 进行安装。&lt;/li>
&lt;li>&lt;strong>&lt;code>README.md&lt;/code>&lt;/strong>: 项目的说明文件，介绍如何设置、运行和使用该项目。&lt;/li>
&lt;/ul>
&lt;h3 id="app-目录核心应用">&lt;code>app/&lt;/code> 目录：核心应用
&lt;/h3>&lt;p>这是你所有业务逻辑代码的家。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&lt;code>main.py&lt;/code>&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: FastAPI 应用的入口点。&lt;/li>
&lt;li>&lt;strong>内容&lt;/strong>: 创建 FastAPI 实例，挂载中间件 (Middleware)，包含来自 &lt;code>app/api/&lt;/code> 的主路由，并可以定义全局的异常处理程序。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>api/&lt;/code> 目录&lt;/strong>: API 层&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 负责处理 HTTP 请求，定义 API 的路径、参数和响应。这一层应该保持精简，只做请求的接收和响应的返回，具体的业务逻辑和数据库操作应该调用其他模块来完成。&lt;/li>
&lt;li>&lt;strong>&lt;code>v1/&lt;/code>&lt;/strong>: 按版本组织 API 是一个非常好的实践，方便未来升级。&lt;/li>
&lt;li>&lt;strong>&lt;code>v1/endpoints/&lt;/code>&lt;/strong>: 每个 &lt;code>*.py&lt;/code> 文件代表一组相关的 API 路由（例如 &lt;code>users.py&lt;/code> 处理所有 &lt;code>/users&lt;/code> 相关的请求）。&lt;/li>
&lt;li>&lt;strong>&lt;code>v1/api.py&lt;/code>&lt;/strong>: 这个文件导入 &lt;code>endpoints&lt;/code> 中的所有路由，并将它们组合成一个单一的 &lt;code>APIRouter&lt;/code>，然后这个 &lt;code>APIRouter&lt;/code> 会被 &lt;code>main.py&lt;/code> 包含进去。这让 API 版本的管理变得非常清晰。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>core/&lt;/code> 目录&lt;/strong>: 核心配置&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 存放应用的全局配置和核心功能。&lt;/li>
&lt;li>&lt;strong>&lt;code>config.py&lt;/code>&lt;/strong>: 使用 Pydantic 的 &lt;code>BaseSettings&lt;/code> 读取 &lt;code>.env&lt;/code> 文件和环境变量，为整个应用提供一个统一的配置对象。&lt;/li>
&lt;li>&lt;strong>&lt;code>security.py&lt;/code>&lt;/strong>: 处理所有与安全相关的功能，如密码的哈希和验证、JWT 令牌的创建和解码。&lt;/li>
&lt;li>&lt;strong>&lt;code>logger.py&lt;/code>&lt;/strong>: 日志系统的配置和工具函数，提供统一的日志记录接口，支持不同级别的日志输出、文件轮转和格式化配置。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>db/&lt;/code> 目录&lt;/strong>: 数据库连接与会话&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 管理数据库的连接和会话。&lt;/li>
&lt;li>&lt;strong>&lt;code>session.py&lt;/code>&lt;/strong>: 定义 SQLAlchemy 的 &lt;code>engine&lt;/code> 和 &lt;code>SessionLocal&lt;/code>（会话工厂）。&lt;/li>
&lt;li>&lt;strong>&lt;code>base.py&lt;/code>&lt;/strong>: 包含 &lt;code>declarative_base()&lt;/code> 的实例，我们所有的 ORM 模型都将继承自这个基类。这使得 Alembic（数据库迁移工具）能够发现我们的模型。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>models/&lt;/code> 目录&lt;/strong>: 数据库模型层&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 定义了与数据库表对应的 SQLAlchemy ORM 模型。每个文件对应一个模型（或一组紧密相关的模型）。这些模型描述了数据的结构。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>schemas/&lt;/code> 目录&lt;/strong>: 数据校验层&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 定义 Pydantic 模型，FastAPI 用它来做数据验证、序列化和文档生成。&lt;/li>
&lt;li>&lt;strong>职责&lt;/strong>:
&lt;ol>
&lt;li>&lt;strong>请求体验证&lt;/strong>: 验证传入的请求体（例如，创建一个新用户时，确保 &lt;code>email&lt;/code> 字段是合法的）。&lt;/li>
&lt;li>&lt;strong>响应体塑形&lt;/strong>: 决定从 API 返回哪些字段（例如，从数据库查询出的用户对象可能包含哈希后的密码，但我们绝不应该在 API 响应中返回它）。&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>通常会为每个模型定义多个 Schema，例如 &lt;code>UserCreate&lt;/code>, &lt;code>UserUpdate&lt;/code>, &lt;code>UserInDB&lt;/code>, &lt;code>User&lt;/code>。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>crud/&lt;/code> 目录&lt;/strong>: 数据操作层&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: &amp;ldquo;Create, Read, Update, Delete&amp;rdquo; 的缩写。这一层封装了所有与数据库的直接交互。&lt;/li>
&lt;li>&lt;strong>职责&lt;/strong>: 将数据库操作（如 &lt;code>db.add(obj)&lt;/code>) 从 API 路由中分离出来。API 路由不应该直接编写 SQLAlchemy 查询语句，而应该调用这里的函数，例如 &lt;code>crud.user.create_user(...)&lt;/code>。这使得代码更易于测试和重用。&lt;/li>
&lt;li>&lt;strong>&lt;code>base.py&lt;/code>&lt;/strong>: 可以定义一个通用的 &lt;code>CRUDBase&lt;/code> 类，包含 &lt;code>get&lt;/code>, &lt;code>get_multi&lt;/code>, &lt;code>create&lt;/code>, &lt;code>update&lt;/code>, &lt;code>delete&lt;/code> 等通用方法，然后具体的 &lt;code>crud_user.py&lt;/code> 只需继承它并添加特定逻辑即可。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>&lt;code>dependencies/&lt;/code> 目录&lt;/strong>: 依赖注入&lt;/p>
&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 存放 FastAPI 的依赖项。依赖注入是 FastAPI 的一个核心特性。&lt;/li>
&lt;li>&lt;strong>职责&lt;/strong>: 创建可重用的依赖项，例如 &lt;code>get_db&lt;/code> 用于为每个请求提供一个数据库会话，并在请求结束后关闭它；&lt;code>get_current_user&lt;/code> 用于验证 JWT 令牌并返回当前登录的用户。这些依赖项可以在 API 路径操作函数中直接使用。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="tests-目录测试">&lt;code>tests/&lt;/code> 目录：测试
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 存放所有的测试代码。保持测试代码与应用代码分离。&lt;/li>
&lt;li>&lt;strong>&lt;code>conftest.py&lt;/code>&lt;/strong>: Pytest 的配置文件，用于定义测试范围内的 fixtures（例如，创建一个临时的测试数据库、一个用于发送请求的 &lt;code>TestClient&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>目录结构&lt;/strong>: 测试目录的结构最好能镜像 &lt;code>app/&lt;/code> 目录的结构，这样可以很容易地找到对应模块的测试。&lt;/li>
&lt;/ul>
&lt;h3 id="logs-目录日志文件">&lt;code>logs/&lt;/code> 目录：日志文件
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>作用&lt;/strong>: 存储应用运行时产生的日志文件。&lt;/li>
&lt;li>&lt;strong>自动创建&lt;/strong>: 该目录由 &lt;code>app/core/logger.py&lt;/code> 在首次运行时自动创建，无需手动创建。&lt;/li>
&lt;li>&lt;strong>文件轮转&lt;/strong>: 采用日志轮转机制，当主日志文件达到设定大小（如10MB）时，会自动轮转为历史文件，保持最近的5个日志文件。&lt;/li>
&lt;li>&lt;strong>建议&lt;/strong>: 在 &lt;code>.gitignore&lt;/code> 中添加 &lt;code>logs/&lt;/code> 目录，避免将日志文件提交到版本控制系统。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="示例代码">示例代码
&lt;/h2>&lt;p>下面是一些关键文件的示例代码，以帮助你更好地理解它们的具体实现。&lt;/p>
&lt;h4 id="appmainpy">&lt;code>app/main.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">FastAPI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.api.v1&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">api&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.core.config&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">settings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">FastAPI&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">title&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">PROJECT_NAME&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">openapi_url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">API_V1_STR&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/openapi.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 包含 v1 版本的 API 路由&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">include_router&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">api_router&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prefix&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">API_V1_STR&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">read_root&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;message&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Welcome to this fantastic app!&amp;#34;&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appapiv1apipy">&lt;code>app/api/v1/api.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">APIRouter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.api.v1.endpoints&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">items&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">api_router&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">APIRouter&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 包含 users 和 items 的路由&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">api_router&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">include_router&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">router&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prefix&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/users&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tags&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;users&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">api_router&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">include_router&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">router&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prefix&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/items&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tags&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;items&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appapiv1endpointsuserspy">&lt;code>app/api/v1/endpoints/users.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">APIRouter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Depends&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">HTTPException&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">List&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">crud&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">models&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">schemas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.dependencies&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">common&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">router&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">APIRouter&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@router.post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response_model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">schemas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">create_user&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">user&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">schemas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">UserCreate&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Depends&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">common&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_db&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db_user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">crud&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_user_by_email&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">email&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">email&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">db_user&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">HTTPException&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">status_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">400&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">detail&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Email already registered&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">crud&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@router.get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response_model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">schemas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">read_users&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">skip&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">limit&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Depends&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">common&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_db&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">users&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">crud&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_users&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">skip&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">skip&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">limit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">limit&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">users&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appcoreconfigpy">&lt;code>app/core/config.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pydantic_settings&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BaseSettings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Settings&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseSettings&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROJECT_NAME&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;FastAPI Project&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">API_V1_STR&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;/api/v1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 数据库配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">#SQLALCHEMY_DATABASE_URI: str = &amp;#34;sqlite:///./test.db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SQLALCHEMY_DATABASE_URI&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;DATABASE_URL&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;postgresql://user:password@localhost/db&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># JWT 配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SECRET_KEY&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;a_very_secret_key&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ALGORITHM&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;HS256&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ACCESS_TOKEN_EXPIRE_MINUTES&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">class&lt;/span> &lt;span class="nc">Config&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">env_file&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;.env&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">settings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Settings&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appschemasuserpy">&lt;code>app/schemas/user.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pydantic&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BaseModel&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">EmailStr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">typing&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Optional&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 基础模型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserBase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseModel&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">EmailStr&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">full_name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_active&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建时需要的字段 (继承自 Base，并添加 password)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserCreate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">UserBase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">password&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 更新时需要的字段 (所有字段都可选)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserUpdate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">UserBase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">password&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 存储在数据库中的模型 (包含 hashed_password)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">UserInDBBase&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">UserBase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">hashed_password&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">class&lt;/span> &lt;span class="nc">Config&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">from_attributes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span> &lt;span class="c1"># Pydantic v2 orm_mode for Pydantic v1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 从 API 返回给用户的模型 (不包含密码)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">User&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">UserBase&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">is_active&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">bool&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">class&lt;/span> &lt;span class="nc">Config&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">from_attributes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appcrudcrud_userpy">&lt;code>app/crud/crud_user.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.core.security&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">get_password_hash&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">models&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">schemas&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">user_id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_user_by_email&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">email&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">email&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">email&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_users&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">skip&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">limit&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">int&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">offset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">skip&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">limit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">limit&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">all&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">create_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Session&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">schemas&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">UserCreate&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">hashed_password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_password_hash&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db_user&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">models&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">email&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">email&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">full_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">full_name&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">hashed_password&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">hashed_password&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db_user&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">refresh&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">db_user&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">db_user&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appdependenciescommonpy">&lt;code>app/dependencies/common.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">sqlalchemy.orm&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Session&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.db.session&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SessionLocal&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 依赖项：为每个请求创建一个独立的数据库会话&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_db&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SessionLocal&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">yield&lt;/span> &lt;span class="n">db&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="appcoreloggerpy">&lt;code>app/core/logger.py&lt;/code>
&lt;/h4>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging.handlers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pathlib&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Path&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">app.core.config&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">settings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">setup_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Logger&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 设置应用日志记录器
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> name: 日志记录器名称，默认为调用模块的名称
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Returns:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 配置好的日志记录器实例
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 避免重复配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">handlers&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 设置日志级别&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_level&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">settings&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;LOG_LEVEL&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setLevel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">getattr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">log_level&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 创建日志格式&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">formatter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Formatter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fmt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="si">%(asctime)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(name)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(levelname)s&lt;/span>&lt;span class="s1"> - &lt;/span>&lt;span class="si">%(message)s&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">datefmt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1"> %H:%M:%S&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 控制台处理器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">console_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">StreamHandler&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">console_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">console_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 文件处理器（带轮转）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Path&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;logs&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_dir&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">mkdir&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">exist_ok&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_handler&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">handlers&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">RotatingFileHandler&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">filename&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">log_dir&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="s2">&amp;#34;app.log&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">maxBytes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1024&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 10MB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">backupCount&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">encoding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;utf-8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_handler&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">setFormatter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">formatter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">addHandler&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_handler&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 创建默认的应用日志记录器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app_logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">setup_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;fastapi_app&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">get_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Logger&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 获取日志记录器实例
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Args:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> name: 日志记录器名称，如果为None则使用默认应用日志记录器
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Returns:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 日志记录器实例
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">app_logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">setup_logger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这个结构为你提供了一个坚实的起点。你可以根据项目的具体需求，在这个基础上进行调整和扩展。&lt;/p></description></item><item><title>一个标准的软件项目结构</title><link>https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/</link><pubDate>Wed, 23 Jul 2025 22:58:35 +0800</pubDate><guid>https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/</guid><description>&lt;img src="https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/images/index/index.png" alt="Featured image of post 一个标准的软件项目结构" />&lt;h2 id="目录">目录
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="#%e5%ae%8c%e6%95%b4%e7%9a%84%e9%a1%b9%e7%9b%ae%e7%bb%93%e6%9e%84%e7%a4%ba%e4%be%8b" >完整的项目结构示例(web python)&lt;/a>&lt;/li>
&lt;li>代码结构和编写规范
&lt;ul>
&lt;li>&lt;a class="link" href="#best-practices-functions" >📚《如何写出易读、易维护的函数：避免深层嵌套与隐式副作用》&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="核心结构概览">核心结构概览
&lt;/h2>&lt;p>在深入探讨每个部分之前，这里是一个标准项目结构的高度概括，分为“基础必备”和“推荐包含”两部分。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-plaintext" data-lang="plaintext">&lt;span class="line">&lt;span class="cl">/my-awesome-project
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .gitignore # 必备：告诉 Git 忽略哪些文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── LICENSE # 必备：项目许可证
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── README.md # 必备：项目介绍和说明
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── package.json # 必备：依赖管理 (示例为 Node.js)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── src/ # 必备：存放所有源代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── tests/ # 必备：存放所有测试代码
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .github/ # 推荐：CI/CD 工作流 (例如 GitHub Actions)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── config/ # 推荐：存放配置文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── dist/ # 推荐：存放编译后的输出文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── docs/ # 推荐：存放项目文档
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── scripts/ # 推荐：存放自动化脚本
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>一个标准的软件项目结构，能够帮助团队成员快速理解项目，降低维护成本，并促进协作。虽然不同语言和框架的项目结构有所差异，但一些通用的最佳实践和目录结构是相通的。本文将介绍一个典型的、与语言无关的软件项目结构。&lt;/p>
&lt;h2 id="为什么项目结构很重要">为什么项目结构很重要？
&lt;/h2>&lt;p>一个良好定义的项目结构可以：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>提高可读性&lt;/strong>：新人可以快速找到他们需要的文件。&lt;/li>
&lt;li>&lt;strong>促进协作&lt;/strong>：统一的结构让团队成员更容易协作开发和进行代码审查。&lt;/li>
&lt;li>&lt;strong>简化维护&lt;/strong>：当所有东西都在可预测的位置时，调试和添加新功能会更容易。&lt;/li>
&lt;li>&lt;strong>自动化&lt;/strong>：清晰的结构便于设置构建、测试和部署的自动化脚本。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="顶层文件">顶层文件
&lt;/h2>&lt;p>项目根目录通常包含一些元数据文件，用于描述项目、配置环境和定义依赖。&lt;/p>
&lt;ul>
&lt;li>&lt;code>README.md&lt;/code>：项目的入口。它应该包含项目的简介、如何安装和运行、如何贡献等信息。这是一个项目最重要的文档。&lt;/li>
&lt;li>&lt;code>LICENSE&lt;/code>：软件许可证文件，例如 MIT、Apache 2.0 或 GPL。它告诉其他人他们可以使用你的代码做什么。&lt;/li>
&lt;li>&lt;code>.gitignore&lt;/code>：告诉 Git 哪些文件或目录应该被忽略，不纳入版本控制。例如编译产生的文件（&lt;code>build/&lt;/code>, &lt;code>dist/&lt;/code>）、依赖包（&lt;code>node_modules/&lt;/code>）和敏感信息（&lt;code>.env&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>依赖管理文件&lt;/strong>：
&lt;ul>
&lt;li>&lt;code>package.json&lt;/code> (Node.js)&lt;/li>
&lt;li>&lt;code>requirements.txt&lt;/code> or &lt;code>pyproject.toml&lt;/code> (Python)&lt;/li>
&lt;li>&lt;code>pom.xml&lt;/code> or &lt;code>build.gradle&lt;/code> (Java/Kotlin)&lt;/li>
&lt;li>&lt;code>go.mod&lt;/code> (Go)&lt;/li>
&lt;li>&lt;code>Cargo.toml&lt;/code> (Rust)
这个文件定义了项目所需的第三方库和依赖项。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>CI/CD 配置文件&lt;/strong>:
&lt;ul>
&lt;li>&lt;code>.github/workflows/&lt;/code> (GitHub Actions)&lt;/li>
&lt;li>&lt;code>.gitlab-ci.yml&lt;/code> (GitLab CI/CD)&lt;/li>
&lt;li>&lt;code>Jenkinsfile&lt;/code> (Jenkins)
这些文件定义了持续集成和持续部署的流程。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="核心目录结构">核心目录结构
&lt;/h2>&lt;h3 id="1-src-或-lib---源代码">1. &lt;code>src&lt;/code> 或 &lt;code>lib&lt;/code> - 源代码
&lt;/h3>&lt;p>这是项目的心脏，包含了所有的核心业务逻辑。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>src&lt;/code> (Source)&lt;/strong>: 这个命名最常见。所有你写的源代码都应该放在这里。&lt;/li>
&lt;li>&lt;strong>&lt;code>lib&lt;/code> (Library)&lt;/strong>: 在某些项目中（特别是库项目）会使用 &lt;code>lib&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>&lt;code>src&lt;/code> 目录内部的组织方式通常有两种：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>按层组织 (Layer-based)&lt;/strong>:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── controllers/ # 或 routes/ - 处理HTTP请求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── services/ # 业务逻辑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── models/ # 数据模型或数据库实体
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── repositories/ # 数据访问层
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── utils/ # 通用工具函数
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>按功能组织 (Feature-based)&lt;/strong>:
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── user/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── user.controller.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── user.service.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── user.model.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── product/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── product.controller.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── product.service.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── product.model.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── auth/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── auth.controller.ts
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── auth.service.ts
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>对于大型项目，按功能组织通常更具扩展性。&lt;/li>
&lt;/ul>
&lt;h3 id="2-tests---测试代码">2. &lt;code>tests&lt;/code> - 测试代码
&lt;/h3>&lt;p>测试是保证软件质量的关键。&lt;code>tests&lt;/code> 目录存放所有的测试代码。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── unit/ # 单元测试，测试单个函数或模块
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── services/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── utils/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── integration/ # 集成测试，测试多个模块协同工作
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── e2e/ # 端到端测试，模拟真实用户场景
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有些项目会将测试文件和源代码文件放在一起，例如 &lt;code>user.service.ts&lt;/code> 和 &lt;code>user.service.spec.ts&lt;/code>。这两种方式各有优劣，关键是保持一致性。&lt;/p>
&lt;h3 id="3-docs---文档">3. &lt;code>docs&lt;/code> - 文档
&lt;/h3>&lt;p>存放项目的所有文档。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>API 文档&lt;/strong>: 使用 Swagger/OpenAPI 规范自动生成，或手动编写。&lt;/li>
&lt;li>&lt;strong>架构设计&lt;/strong>: 描述系统架构、组件和数据流。&lt;/li>
&lt;li>&lt;strong>贡献指南&lt;/strong>: &lt;code>CONTRIBUTING.md&lt;/code> 也可以放在根目录。&lt;/li>
&lt;li>&lt;strong>用户手册&lt;/strong>: 如果是提供给最终用户的软件。&lt;/li>
&lt;/ul>
&lt;h3 id="4-dist-或-build---构建输出">4. &lt;code>dist&lt;/code> 或 &lt;code>build&lt;/code> - 构建输出
&lt;/h3>&lt;p>存放编译、打包或压缩后的文件。这些文件是最终部署到生产环境或分发给用户的。这个目录通常会被添加到 &lt;code>.gitignore&lt;/code> 中，因为它可以从源代码重新生成。&lt;/p>
&lt;h3 id="5-config---配置文件">5. &lt;code>config&lt;/code> - 配置文件
&lt;/h3>&lt;p>存放项目的配置文件。一个好的实践是为不同环境（开发、测试、生产）提供不同的配置文件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">config/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── default.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── development.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── production.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── test.json
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>注意&lt;/strong>：永远不要将密码、API 密钥等敏感信息硬编码在代码或配置文件中，并提交到版本库。使用环境变量（如 &lt;code>.env&lt;/code> 文件）来管理这些信息。&lt;code>.env&lt;/code> 文件应该被添加到 &lt;code>.gitignore&lt;/code> 中，但可以提供一个 &lt;code>.env.example&lt;/code> 文件作为模板。&lt;/p>
&lt;h3 id="6-scripts---脚本">6. &lt;code>scripts&lt;/code> - 脚本
&lt;/h3>&lt;p>存放用于自动化任务的脚本。&lt;/p>
&lt;ul>
&lt;li>&lt;code>build.sh&lt;/code>: 构建项目。&lt;/li>
&lt;li>&lt;code>deploy.sh&lt;/code>: 部署项目。&lt;/li>
&lt;li>&lt;code>db_migration.sh&lt;/code>: 数据库迁移。&lt;/li>
&lt;li>&lt;code>ci_check.sh&lt;/code>: CI/CD 流程中运行的检查。&lt;/li>
&lt;/ul>
&lt;h3 id="7-assets-或-public---静态资源">7. &lt;code>assets&lt;/code> 或 &lt;code>public&lt;/code> - 静态资源
&lt;/h3>&lt;p>对于 Web 应用，这个目录用于存放静态文件，如图片、CSS 和 JavaScript 文件。&lt;/p>
&lt;h3 id="8-examples---示例代码">8. &lt;code>examples&lt;/code> - 示例代码
&lt;/h3>&lt;p>如果你的项目是一个库或框架，提供一个 &lt;code>examples&lt;/code> 目录会非常有帮助。它向用户展示了如何使用你的库。&lt;/p>
&lt;hr>
&lt;h2 id="完整的项目结构示例">完整的项目结构示例
&lt;/h2>&lt;h3 id="通用-web-应用项目结构示例">通用 Web 应用项目结构示例：
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">my-awesome-project/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .github/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── workflows/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── ci.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── config/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── default.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── production.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── docs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── api/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── architecture.md
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── scripts/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── build.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── deploy.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── src/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── auth/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── auth.controller.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── auth.service.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── user/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── user.controller.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── user.service.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── user.model.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── app.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── tests/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── integration/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── auth.integration.test.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── unit/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── user.service.test.js
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .env.example
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .gitignore
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── LICENSE
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── package.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── README.md
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="通用python应用项目结构示例">通用python应用项目结构示例
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">my_project/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── my_project/ # 源代码包（Python 包）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── __init__.py # 使目录成为 Python 包
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── main.py # 应用入口（可选）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── cli.py # 命令行接口（可选）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── config.py # 配置文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── models/ # 数据模型（如数据库模型）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── services/ # 业务逻辑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── utils/ # 工具函数
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── tests/ # 单元测试（可选放外面，见下）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── test_models.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── test_services.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── tests/ # 推荐：测试放在项目根目录下
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── __init__.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── test_main.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── test_cli.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── docs/ # 文档
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── index.rst
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── scripts/ # 部署或辅助脚本
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── deploy.sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── examples/ # 使用示例
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── example_usage.py
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .gitignore # Git 忽略文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── .python-version # pyenv 使用（可选）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── pyproject.toml # 推荐：现代 Python 项目配置（替代 setup.py）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── setup.cfg # 或 setup.py（传统方式）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── requirements.txt # 依赖列表（开发/生产）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── requirements-dev.txt # 开发依赖
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── README.md # 项目说明
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── LICENSE # 开源许可证
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── CHANGELOG.md # 版本变更日志（可选）
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/images/index/index-1.png"
width="871"
height="215"
srcset="https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/images/index/index-1_hu8309260510029023877.png 480w, https://www.zata.cc/p/%E4%B8%80%E4%B8%AA%E6%A0%87%E5%87%86%E7%9A%84%E8%BD%AF%E4%BB%B6%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84/images/index/index-1_hu10365333124005281503.png 1024w"
loading="lazy"
alt="关于项目代码文件夹如何放置"
class="gallery-image"
data-flex-grow="405"
data-flex-basis="972px"
>&lt;/p>
&lt;h2 id="代码结构和编写规范">代码结构和编写规范
&lt;/h2>&lt;h3 id="best-practices-functions">📚如何写出易读、易维护的函数：避免深层嵌套与隐式副作用
&lt;/h3>&lt;blockquote>
&lt;p>适合：Python、JavaScript 等支持函数式和过程式编程语言的开发者&lt;br>
目标：提升代码可读性、降低维护成本、减少 bug&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h4 id="一问题为什么有些函数看起来就很累">一、问题：为什么有些函数“看起来就很累”？
&lt;/h4>&lt;p>你有没有遇到过这样的代码？&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_valid&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">update_result&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 修改 result 列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">send_notification&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">log_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Invalid item&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这种代码常见问题：&lt;/p>
&lt;ul>
&lt;li>❌ 缩进太多（3层以上）&lt;/li>
&lt;li>❌ 没有返回值，却修改了外部变量（副作用）&lt;/li>
&lt;li>❌ 逻辑分散，难测试、难复用&lt;/li>
&lt;/ul>
&lt;p>我们来一步步优化它。&lt;/p>
&lt;hr>
&lt;h4 id="二原则一控制嵌套层级建议-3-层">二、原则一：控制嵌套层级（建议 ≤3 层）
&lt;/h4>&lt;h5 id="-原则">✅ 原则
&lt;/h5>&lt;blockquote>
&lt;p>&lt;strong>超过3层的条件或循环嵌套，应通过“提前返回”或“提取函数”来简化。&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;h5 id="-反例嵌套过深">❌ 反例（嵌套过深）
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">check_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_active&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">has_permission&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="-改进使用守卫语句guard-clauses">✅ 改进：使用“守卫语句”（Guard Clauses）
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">check_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_active&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">has_permission&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">False&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">True&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>✅ 优点：&lt;/p>
&lt;ul>
&lt;li>缩进浅，逻辑线性&lt;/li>
&lt;li>每个条件独立清晰&lt;/li>
&lt;li>易于添加日志或错误处理&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="三原则二避免隐式修改引用优先使用输入--输出模式">三、原则二：避免“隐式修改引用”，优先使用“输入 → 输出”模式
&lt;/h4>&lt;h5 id="-问题通过引用修改对象副作用">❌ 问题：通过引用修改对象（副作用）
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">items&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># ❌ 修改了传入的列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">my_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">add_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_list&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;b&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_list&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;] —— 被“偷偷”改了&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>⚠️ 风险：调用者不知道列表会被修改，容易出 bug。&lt;/p>
&lt;h5 id="-改进返回新值不修改原对象">✅ 改进：返回新值，不修改原对象
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">item&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">items&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># ✅ 返回新列表&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">my_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;a&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">new_list&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">add_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_list&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;b&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_list&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># [&amp;#39;a&amp;#39;] —— 原列表不变&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_list&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;] —— 新列表返回&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>✅ 优点：&lt;/p>
&lt;ul>
&lt;li>函数是“纯”的（输入相同，输出相同）&lt;/li>
&lt;li>易测试、可组合、可缓存&lt;/li>
&lt;li>不会意外影响其他代码&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>💡 提示：对于大对象，可以用 &lt;code>copy&lt;/code> 或不可变数据结构（如 Python 的 &lt;code>tuple&lt;/code>、&lt;code>frozenset&lt;/code>，或使用 &lt;code>dataclasses&lt;/code> + &lt;code>frozen=True&lt;/code>）&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h4 id="四原则三拆分长调用链保持职责单一">四、原则三：拆分长调用链，保持职责单一
&lt;/h4>&lt;h5 id="-问题调用链太深像俄罗斯套娃">❌ 问题：调用链太深，像“俄罗斯套娃”
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">handle_request&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fetch_data&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">processed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">validate_and_save&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">processed&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cleaned&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">clean_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">enriched&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enrich_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cleaned&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">formatted&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">format_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">enriched&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">formatted&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>虽然结构清晰，但如果每层都复杂，阅读时要“跳来跳去”。&lt;/p>
&lt;h5 id="-改进策略">✅ 改进策略：
&lt;/h5>&lt;ol>
&lt;li>&lt;strong>提取函数，命名清晰&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">clean_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enrich_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">format_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>&lt;strong>使用注释或文档说明流程&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 处理流程：
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 1. 清洗数据
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 2. 补充信息
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> 3. 格式化输出
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">clean_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">enrich_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">format_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>&lt;strong>考虑使用流水线（Pipeline）模式&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">pipeline&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">clean_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">enrich_data&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">format_data&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">data&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">step&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">pipeline&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">step&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h4 id="五综合案例从难读到清晰">五、综合案例：从“难读”到“清晰”
&lt;/h4>&lt;h5 id="-原始代码嵌套深--引用修改">❌ 原始代码（嵌套深 + 引用修改）
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_users&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">user&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">active&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;INACTIVE&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;NO_USERS&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="-重构后清晰无副作用易测试">✅ 重构后：清晰、无副作用、易测试
&lt;/h5>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">active&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;INACTIVE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_users&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;NO_USERS&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">process_user&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">user&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">user&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">users&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>✅ 优点：&lt;/p>
&lt;ul>
&lt;li>没有嵌套地狱&lt;/li>
&lt;li>不修改外部变量&lt;/li>
&lt;li>每个函数职责单一&lt;/li>
&lt;li>可单独测试 &lt;code>process_user&lt;/code>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="六实用检查清单-">六、实用检查清单 ✅
&lt;/h4>&lt;p>每次写函数时，问自己：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>问题&lt;/th>
&lt;th>是/否&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>函数嵌套超过3层了吗？&lt;/td>
&lt;td>☐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>函数修改了传入的 list/dict 吗？&lt;/td>
&lt;td>☐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>函数没有返回值，但有“副作用”吗？&lt;/td>
&lt;td>☐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>调用链超过5层了吗？&lt;/td>
&lt;td>☐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>能不能给这个函数起个更清晰的名字？&lt;/td>
&lt;td>☐&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>如果任何一个“是”，就考虑重构。&lt;/p>
&lt;hr>
&lt;h4 id="七额外建议">七、额外建议
&lt;/h4>&lt;ul>
&lt;li>使用工具自动检测：
&lt;ul>
&lt;li>Python: &lt;code>pylint&lt;/code>, &lt;code>flake8&lt;/code>（配置 &lt;code>max-nested-blocks=3&lt;/code>）&lt;/li>
&lt;li>JavaScript: &lt;code>ESLint&lt;/code>（&lt;code>max-depth&lt;/code>, &lt;code>max-nested-callbacks&lt;/code>）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>学习函数式编程思想：&lt;strong>纯函数、不可变数据、组合优于嵌套&lt;/strong>&lt;/li>
&lt;li>多写单元测试：你会发现“有副作用的函数”最难测！&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="总结好函数的三大特征">总结：好函数的三大特征
&lt;/h4>&lt;p>🟢 &lt;strong>浅嵌套&lt;/strong>：用“提前返回”代替层层 if&lt;br>
🟢 &lt;strong>无隐式副作用&lt;/strong>：优先返回新值，不修改输入&lt;br>
🟢 &lt;strong>职责单一&lt;/strong>：一个函数只做一件事&lt;/p>
&lt;blockquote>
&lt;p>💬 记住：&lt;br>
&lt;strong>代码是写给人看的，顺便让机器执行。&lt;/strong>&lt;/p>
&lt;/blockquote></description></item><item><title>漂亮的reademe文件使用教程</title><link>https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><pubDate>Tue, 10 Jun 2025 16:09:07 +0800</pubDate><guid>https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/index.png" alt="Featured image of post 漂亮的reademe文件使用教程" />&lt;h3 id="为什么需要一份漂亮的-readme">为什么需要一份漂亮的 README？
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>第一印象：&lt;/strong> 吸引用户和潜在贡献者的关键。&lt;/li>
&lt;li>&lt;strong>清晰文档：&lt;/strong> 帮助他人（以及未来的你）快速理解项目的用途、安装和使用方法。&lt;/li>
&lt;li>&lt;strong>提升专业性：&lt;/strong> 一份结构良好、内容详尽的 README 体现了开发者的严谨和专业。&lt;/li>
&lt;li>&lt;strong>降低沟通成本：&lt;/strong> 提前回答了用户可能遇到的常见问题。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="一份优秀-readme-的核心组成部分">一份优秀 README 的核心组成部分
&lt;/h3>&lt;p>下面是一个推荐的 README 结构，你可以根据自己项目的具体情况进行增删。&lt;/p>
&lt;h4 id="1-项目标题和-logo-header">1. 项目标题和 Logo (Header)
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>标题 (&lt;code>#&lt;/code>)：&lt;/strong> 清晰、简洁的项目名称。&lt;/li>
&lt;li>&lt;strong>Logo (可选)：&lt;/strong> 一个精心设计的 Logo 能极大地提升项目的品牌感和辨识度。将 Logo 居中放置效果更佳。&lt;/li>
&lt;li>&lt;strong>一句话简介 (Tagline)：&lt;/strong> 用一句话精准地概括你的项目是做什么的。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">align&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;center&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;项目主页链接&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;image.png&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;项目Logo&amp;#34;&lt;/span> &lt;span class="na">width&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;80&amp;#34;&lt;/span> &lt;span class="na">height&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;80&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">h1&lt;/span> &lt;span class="na">align&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;center&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>项目标题&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">h1&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">align&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;center&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 这里是一句简短、精炼的话，描述你的项目核心功能。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image.png"
width="1137"
height="243"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image_hu11605065435723215190.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image_hu17782104884909523930.png 1024w"
loading="lazy"
alt="project title"
class="gallery-image"
data-flex-grow="467"
data-flex-basis="1122px"
>&lt;/p>
&lt;h4 id="2-徽章-badges">2. 徽章 (Badges)
&lt;/h4>&lt;p>徽章是简洁传达项目状态的小图标，通常放在标题下方。它们提供了诸如构建状态、代码覆盖率、开源协议、版本号等元信息。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>常用徽章：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>构建状态 (Build Status):&lt;/strong> Travis CI, GitHub Actions&lt;/li>
&lt;li>&lt;strong>代码覆盖率 (Code Coverage):&lt;/strong> Codecov&lt;/li>
&lt;li>&lt;strong>版本号 (Version):&lt;/strong> NPM, PyPI, NuGet&lt;/li>
&lt;li>&lt;strong>许可证 (License):&lt;/strong> MIT, Apache 2.0&lt;/li>
&lt;li>&lt;strong>下载量 (Downloads):&lt;/strong> GitHub, NPM&lt;/li>
&lt;li>&lt;strong>语言 (Language):&lt;/strong> 项目主要开发语言&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>如何生成徽章？&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a class="link" href="https://shields.io/" target="_blank" rel="noopener"
>Shields.io&lt;/a>&lt;/strong> 是最流行的徽章生成服务。你可以根据需要定制各种徽章。
&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-1.png"
width="1912"
height="954"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-1_hu7242589333176750847.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-1_hu17000320764021543328.png 1024w"
loading="lazy"
alt="shields"
class="gallery-image"
data-flex-grow="200"
data-flex-basis="481px"
>
&lt;strong>示例：&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">p&lt;/span> &lt;span class="na">align&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;center&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;链接&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;https://img.shields.io/badge/build-passing-brightgreen&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;Build Status&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;链接&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;https://img.shields.io/badge/license-MIT-blue&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;License&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;链接&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">img&lt;/span> &lt;span class="na">src&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;https://img.shields.io/npm/v/你的包名&amp;#34;&lt;/span> &lt;span class="na">alt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;NPM Version&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">p&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-2.png"
width="1158"
height="252"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-2_hu242448089682791516.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-2_hu7464442155556476175.png 1024w"
loading="lazy"
alt="Badges"
class="gallery-image"
data-flex-grow="459"
data-flex-basis="1102px"
>&lt;/p>
&lt;h4 id="3-项目介绍-introduction">3. 项目介绍 (Introduction)
&lt;/h4>&lt;p>详细介绍你的项目。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>它解决了什么问题？&lt;/strong> (Why?)&lt;/li>
&lt;li>&lt;strong>它有什么核心功能和亮点？&lt;/strong> (What?)&lt;/li>
&lt;li>&lt;strong>它的目标用户是谁？&lt;/strong> (Who?)&lt;/li>
&lt;/ul>
&lt;p>可以配上项目的截图或 GIF 动图，让介绍更生动。&lt;/p>
&lt;h4 id="4-目录-table-of-contents-可选">4. 目录 (Table of Contents) (可选)
&lt;/h4>&lt;p>如果你的 README 很长，一个目录能帮助用户快速导航到感兴趣的部分。&lt;/p>
&lt;p>&lt;strong>示例 (使用 HTML &lt;code>details&lt;/code> 标签创建可折叠目录):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">details&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">summary&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>目录&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">summary&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">ol&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="ni">#关于项目&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>关于项目&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="ni">#快速开始&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>快速开始&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="ni">#使用方法&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>使用方法&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="ni">#贡献指南&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>贡献指南&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">a&lt;/span> &lt;span class="na">href&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="ni">#许可证&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>许可证&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">a&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">li&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">ol&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">details&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-3.png"
width="1170"
height="308"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-3_hu9400040124453538205.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-3_hu8357035411403434356.png 1024w"
loading="lazy"
alt="table of contents"
class="gallery-image"
data-flex-grow="379"
data-flex-basis="911px"
>&lt;/p>
&lt;h4 id="5-快速开始-getting-started--installation">5. 快速开始 (Getting Started / Installation)
&lt;/h4>&lt;p>这是 README 中最重要的部分之一。提供清晰、分步的安装和设置指南。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>先决条件 (Prerequisites):&lt;/strong> 运行你的项目需要哪些环境或依赖？（例如：Node.js v16+, Python 3.9+）&lt;/li>
&lt;li>&lt;strong>安装步骤 (Installation):&lt;/strong>
&lt;ol>
&lt;li>克隆仓库: &lt;code>git clone https://github.com/your_username/your_project.git&lt;/code>&lt;/li>
&lt;li>进入目录: &lt;code>cd your_project&lt;/code>&lt;/li>
&lt;li>安装依赖: &lt;code>npm install&lt;/code> 或 &lt;code>pip install -r requirements.txt&lt;/code>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>使用代码块 (&lt;code>```&lt;/code>) 来展示命令，并指明语言类型以获得语法高亮。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 快速开始
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">### 环境要求
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">*&lt;/span> Node.js (&amp;gt;=16.0.0)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">*&lt;/span> npm
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">### 安装步骤
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">1.&lt;/span> 克隆本仓库到本地
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ``&lt;span class="sb">`sh
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb"> git clone https://github.com/your_username/your_project.git
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb"> `&lt;/span>`&lt;span class="sb">`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb">2. 安装依赖
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb"> `&lt;/span>`&lt;span class="sb">`sh
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb"> npm install
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sb"> `&lt;/span>``
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-4.png"
width="1176"
height="441"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-4_hu17625195676906555105.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-4_hu3754443336907303000.png 1024w"
loading="lazy"
alt="getting started"
class="gallery-image"
data-flex-grow="266"
data-flex-basis="640px"
>&lt;/p>
&lt;h4 id="6-使用方法-usage--examples">6. 使用方法 (Usage / Examples)
&lt;/h4>&lt;p>展示如何使用你的项目。提供清晰的代码示例，并对关键部分加以解释。如果可能，提供一个动态演示（GIF）。&lt;/p>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 使用方法
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">下面是一个基础的使用示例：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">```javascript
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">myLibrary&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;my-library&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">myLibrary&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">doSomething&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 配置选项
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">result&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">```&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">更多高级用法，请参考 [&lt;span class="nt">官方文档&lt;/span>](&lt;span class="na">链接到你的文档&lt;/span>).
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-5.png"
width="1176"
height="336"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-5_hu7119526566778283073.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-5_hu6234087168185455779.png 1024w"
loading="lazy"
alt="Usage"
class="gallery-image"
data-flex-grow="350"
data-flex-basis="840px"
>&lt;/p>
&lt;h4 id="7-功能特性-features">7. 功能特性 (Features)
&lt;/h4>&lt;p>使用列表清晰地展示项目的主要功能。&lt;/p>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 功能特性
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">*&lt;/span> ✨ &lt;span class="gs">**特性一：**&lt;/span> 简洁高效的 API 设计。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">*&lt;/span> 🚀 &lt;span class="gs">**特性二：**&lt;/span> 闪电般的执行速度。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">*&lt;/span> 🎨 &lt;span class="gs">**特性三：**&lt;/span> 高度可定制化的主题。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-6.png"
width="1177"
height="181"
srcset="https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-6_hu3462696930807253426.png 480w, https://www.zata.cc/p/%E6%BC%82%E4%BA%AE%E7%9A%84reademe%E6%96%87%E4%BB%B6%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/images/index/image-6_hu790766124603196859.png 1024w"
loading="lazy"
alt="features"
class="gallery-image"
data-flex-grow="650"
data-flex-basis="1560px"
>&lt;/p>
&lt;p>&lt;em>(使用 Emoji 可以让列表更生动)&lt;/em>&lt;/p>
&lt;h4 id="8-贡献指南-contributing">8. 贡献指南 (Contributing)
&lt;/h4>&lt;p>如果你希望这是一个开源项目，并欢迎他人贡献，请提供明确的指南。&lt;/p>
&lt;ul>
&lt;li>说明你欢迎什么样的贡献（Bug 修复、新功能、文档改进等）。&lt;/li>
&lt;li>提供贡献流程（Fork -&amp;gt; Create Branch -&amp;gt; Commit -&amp;gt; Pull Request）。&lt;/li>
&lt;li>链接到 &lt;code>CONTRIBUTING.md&lt;/code> 文件以获取更详细的说明。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 贡献指南
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">我们欢迎任何形式的贡献！请阅读我们的 &lt;span class="ge">**&lt;/span>[&lt;span class="nt">CONTRIBUTING.md&lt;/span>](&lt;span class="na">CONTRIBUTING.md&lt;/span>)** 文件来了解我们的代码规范和提交流程。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="9-许可证-license">9. 许可证 (License)
&lt;/h4>&lt;p>明确你的项目使用的开源许可证。这对于使用者和贡献者都至关重要。&lt;/p>
&lt;p>&lt;strong>示例：&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="gu">## 许可证
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="gu">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">本项目使用 MIT 许可证。详情请见 [&lt;span class="nt">LICENSE&lt;/span>](&lt;span class="na">LICENSE&lt;/span>) 文件。
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="10-致谢与联系方式-acknowledgments--contact">10. 致谢与联系方式 (Acknowledgments &amp;amp; Contact)
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>致谢 (Acknowledgments):&lt;/strong> 感谢那些为你项目提供过帮助的个人、项目或资源。&lt;/li>
&lt;li>&lt;strong>联系方式 (Contact):&lt;/strong> 提供你的联系方式，如邮箱或社交媒体链接。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="markdown-美化技巧">Markdown 美化技巧
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>代码块语法高亮：&lt;/strong> 在 &lt;code>```&lt;/code> 后面添加语言名称，如 &lt;code>javascript&lt;/code>, &lt;code>python&lt;/code>, &lt;code>sh&lt;/code>。&lt;/li>
&lt;li>&lt;strong>表格 (Tables):&lt;/strong> 用于展示结构化数据。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">| 功能 | 描述 |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">| :--- | :--- |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">| A | 功能A的详细描述 |
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">| B | 功能B的详细描述 |
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>折叠区域 (Collapsible Sections):&lt;/strong> 使用 HTML 的 &lt;code>&amp;lt;details&amp;gt;&lt;/code> 和 &lt;code>&amp;lt;summary&amp;gt;&lt;/code> 标签来隐藏长段落或代码块。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">details&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">summary&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>点击查看错误日志&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">summary&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">pre&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;&lt;/span>&lt;span class="nt">code&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ... 大段的日志内容 ...
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">code&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">pre&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">details&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>引用 (Blockquotes):&lt;/strong> 使用 &lt;code>&amp;gt;&lt;/code> 来突出显示重要说明。
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-markdown" data-lang="markdown">&lt;span class="line">&lt;span class="cl">&lt;span class="k">&amp;gt; &lt;/span>&lt;span class="ge">**注意：** 这是一个重要的提示。
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>使用 Emoji：&lt;/strong> 适当地使用 Emoji (如 ✨, 🚀, 💡, 🐛) 可以让你的 README 更具活力和可读性。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="实用工具推荐">实用工具推荐
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>README 模板生成器:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>&lt;a class="link" href="https://readme.so/editor" target="_blank" rel="noopener"
>readme.so&lt;/a>:&lt;/strong> 一个非常棒的在线编辑器，可以让你通过点击和填写来生成一个结构完整的 README。&lt;/li>
&lt;li>&lt;strong>&lt;a class="link" href="https://www.makeareadme.com/" target="_blank" rel="noopener"
>Make a README&lt;/a>:&lt;/strong> 提供最佳实践指导和模板。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>徽章生成:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>&lt;a class="link" href="https://shields.io/" target="_blank" rel="noopener"
>Shields.io&lt;/a>:&lt;/strong> 生成各种状态徽章的首选。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>GIF 录制工具:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>Windows/macOS:&lt;/strong> &lt;strong>&lt;a class="link" href="https://www.screentogif.com/" target="_blank" rel="noopener"
>ScreenToGif&lt;/a>&lt;/strong>, &lt;strong>&lt;a class="link" href="https://www.cockos.com/licecap/" target="_blank" rel="noopener"
>LICEcap&lt;/a>&lt;/strong>, &lt;strong>Giphy Capture&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Markdown 编辑器:&lt;/strong>
&lt;ul>
&lt;li>&lt;strong>VS Code:&lt;/strong> 内置强大的 Markdown 预览功能。&lt;/li>
&lt;li>&lt;strong>Typora:&lt;/strong> 所见即所得的 Markdown 编辑器，非常优雅。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="优秀-readme-案例学习">优秀 README 案例学习
&lt;/h3>&lt;p>没有什么比直接看好的例子更有效了。去看看这些 GitHub 上的项目，学习它们的优点：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a class="link" href="https://github.com/vuejs/vue" target="_blank" rel="noopener"
>Vue.js&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a class="link" href="https://github.com/microsoft/vscode" target="_blank" rel="noopener"
>VS Code&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a class="link" href="https://github.com/awesome-selfhosted/awesome-selfhosted" target="_blank" rel="noopener"
>Awesome-Selfhosted&lt;/a>&lt;/strong>&lt;/li>
&lt;li>&lt;strong>&lt;a class="link" href="https://github.com/withfig/fig" target="_blank" rel="noopener"
>Fig&lt;/a>&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>希望这份教程能帮助你打造出既漂亮又实用的 &lt;code>README.md&lt;/code>！祝你编码愉快！&lt;/p></description></item><item><title>软件架构设计-培养软件架构师的思维</title><link>https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/</link><pubDate>Wed, 23 Apr 2025 17:30:33 +0800</pubDate><guid>https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/</guid><description>&lt;img src="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/index.png" alt="Featured image of post 软件架构设计-培养软件架构师的思维" />&lt;h2 id="软件架构图示例">软件架构图示例
&lt;/h2>&lt;p>参考
&lt;a class="link" href="https://zhuanlan.zhihu.com/p/269201440" target="_blank" rel="noopener"
>知乎 - 亿图&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image.png"
width="1440"
height="1197"
srcset="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image_hu10348735545298179075.png 480w, https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image_hu11695735567700264844.png 1024w"
loading="lazy"
alt="应用架构图"
class="gallery-image"
data-flex-grow="120"
data-flex-basis="288px"
>
&lt;img src="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-1.png"
width="1440"
height="1226"
srcset="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-1_hu13794889289846922807.png 480w, https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-1_hu1841214138771940844.png 1024w"
loading="lazy"
alt="产品架构图"
class="gallery-image"
data-flex-grow="117"
data-flex-basis="281px"
>
&lt;img src="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-2.png"
width="1440"
height="1056"
srcset="https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-2_hu14271816848713330345.png 480w, https://www.zata.cc/p/%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1-%E5%9F%B9%E5%85%BB%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E5%B8%88%E7%9A%84%E6%80%9D%E7%BB%B4/images/index/image-2_hu5688936680846073344.png 1024w"
loading="lazy"
alt="数据架构"
class="gallery-image"
data-flex-grow="136"
data-flex-basis="327px"
>&lt;/p>
&lt;h2 id="第一部分软件架构基础">第一部分：软件架构基础
&lt;/h2>&lt;h3 id="1-什么是软件架构">1. 什么是软件架构？
&lt;/h3>&lt;p>软件开发早期阶段！！！&lt;/p>
&lt;p>软件架构设计是一个在软件开发早期阶段进行的关键过程，软件架构是软件系统的高层次结构，定义了系统的组件、它们之间的关系以及指导系统设计和演化的原则。架构关注系统的非功能性需求（如性能、可扩展性、安全性）和功能性需求。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>核心目标&lt;/strong>：
&lt;ul>
&lt;li>满足功能需求&lt;/li>
&lt;li>确保系统质量（如可维护性、可靠性）&lt;/li>
&lt;li>平衡开发成本和长期维护成本&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="2-软件架构设计的重要性">2. 软件架构设计的重要性
&lt;/h3>&lt;p>软件架构设计的重要性主要体现在以下几个方面：&lt;/p>
&lt;ul>
&lt;li>沟通的桥梁： 架构为不同的利益相关者（如开发人员、项目经理、客户等）提供了一个共同理解系统的基础，方便沟通和协作。&lt;/li>
&lt;li>早期决策： 架构设计涉及一系列关键决策，这些决策在项目早期做出，对后续的开发、部署和维护产生深远影响。正确的架构决策可以避免后期昂贵的修改和返工。&lt;/li>
&lt;li>质量属性的保障： 架构设计直接影响系统的各种质量属性，如性能、安全性、可伸缩性、可靠性、可维护性、可扩展性等。通过合理的架构设计，可以更好地满足这些非功能性需求。&lt;/li>
&lt;li>系统演进的基础： 良好的架构能够适应需求的变化和技术的发展，支持系统的长期演进和维护。&lt;/li>
&lt;li>风险规避： 通过架构设计，可以识别潜在的技术风险和挑战，并提前制定应对策略。&lt;/li>
&lt;li>指导开发： 架构为开发团队提供了清晰的指导和约束，确保各个模块能够有效地集成和协同工作。&lt;/li>
&lt;/ul>
&lt;h3 id="3-架构师的角色">3. 架构师的角色
&lt;/h3>&lt;p>架构师负责：&lt;/p>
&lt;ul>
&lt;li>定义系统结构和技术选型。&lt;/li>
&lt;li>平衡业务需求与技术约束。&lt;/li>
&lt;li>与开发团队、产品经理等沟通，确保架构落地。&lt;/li>
&lt;li>持续优化架构以适应变化。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第二部分软件架构设计原则">第二部分：软件架构设计原则
&lt;/h2>&lt;h3 id="软件架构设计的核心要素通常包括">软件架构设计的核心要素通常包括：
&lt;/h3>&lt;p>组件（Components）： 系统中的主要计算单元或数据存储。&lt;/p>
&lt;p>连接器（Connectors）： 组件之间交互的机制，如函数调用、消息传递、共享数据等。&lt;/p>
&lt;p>配置（Configuration）： 组件和连接器的特定组织方式，描述了系统的整体结构。&lt;/p>
&lt;p>约束（Constraints）： 对架构设计选择的限制，可能来自技术、业务或组织等方面。&lt;/p>
&lt;p>原理（Principles）： 指导设计决策的基本规则和信念。&lt;/p>
&lt;p>软件架构设计的核心原则包括：&lt;/p>
&lt;p>关注点分离 (Separation of Concerns): 将系统的不同功能或职责划分到不同的模块或组件中，降低耦合度。&lt;/p>
&lt;p>高内聚低耦合 (High Cohesion, Low Coupling): 模块内部的功能应该紧密相关（高内聚），模块之间的依赖关系应该尽可能少（低耦合）。&lt;/p>
&lt;p>单一职责原则 (Single Responsibility Principle): 每个模块或组件应该只负责一项特定的功能。&lt;/p>
&lt;p>抽象 (Abstraction): 隐藏底层的复杂实现细节，提供简洁易懂的接口。&lt;/p>
&lt;p>模块化 (Modularity): 将系统划分为独立的、可替换的模块，便于开发、测试和维护。&lt;/p>
&lt;p>可扩展性 (Scalability): 系统应能够方便地进行横向或纵向扩展，以应对不断增长的用户量和数据量。&lt;/p>
&lt;p>可测试性 (Testability): 架构设计应便于对各个组件和整个系统进行测试。&lt;/p>
&lt;p>可维护性 (Maintainability): 清晰、文档化的架构使得系统更容易被理解、修改和维护。&lt;/p>
&lt;p>安全性 (Security): 从架构层面考虑系统的安全需求，构建安全的系统。&lt;/p>
&lt;p>合适性原则 (Suitability): 架构设计应根据项目的具体需求、资源和环境选择最合适的方案，而非盲目追求最新或最复杂的技术。&lt;/p>
&lt;p>简单性原则 (Simplicity): 在满足需求的前提下，应尽量保持架构的简单性，避免过度设计。&lt;/p>
&lt;p>演化性原则 (Evolution): 架构应该能够适应未来的变化和发展，支持逐步演进。&lt;/p>
&lt;h3 id="1-solid-原则">1. SOLID 原则
&lt;/h3>&lt;p>SOLID 是面向对象设计的五大原则，同样适用于架构设计：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>单一职责原则（SRP）&lt;/strong>：一个模块或类只负责一个功能。&lt;/li>
&lt;li>&lt;strong>开闭原则（OCP）&lt;/strong>：对扩展开放，对修改关闭。&lt;/li>
&lt;li>&lt;strong>里氏替换原则（LSP）&lt;/strong>：子类可以替换父类而不影响系统行为。&lt;/li>
&lt;li>&lt;strong>接口隔离原则（ISP）&lt;/strong>：客户端不应被迫依赖不需要的接口。&lt;/li>
&lt;li>&lt;strong>依赖倒置原则（DIP）&lt;/strong>：高层模块不应依赖低层模块，二者都应依赖抽象。&lt;/li>
&lt;/ul>
&lt;h3 id="2-其他关键原则">2. 其他关键原则
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>KISS（Keep It Simple, Stupid）&lt;/strong>：保持设计简单，避免不必要的复杂性。&lt;/li>
&lt;li>&lt;strong>DRY（Don’t Repeat Yourself）&lt;/strong>：避免代码和设计的重复。&lt;/li>
&lt;li>&lt;strong>YAGNI（You Aren’t Gonna Need It）&lt;/strong>：只实现当前需求的功能，避免过度设计。&lt;/li>
&lt;li>&lt;strong>关注点分离（Separation of Concerns）&lt;/strong>：将系统划分为独立的功能模块。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第三部分常见架构模式">第三部分：常见架构模式
&lt;/h2>&lt;h3 id="1-分层架构layered-architecture">1. 分层架构（Layered Architecture）
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>定义&lt;/strong>：将系统分为多个层次（如表示层、业务逻辑层、数据访问层），每层负责特定功能。&lt;/li>
&lt;li>&lt;strong>优点&lt;/strong>：结构清晰，易于维护和测试。&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>：可能导致性能瓶颈，扩展性受限。&lt;/li>
&lt;li>&lt;strong>适用场景&lt;/strong>：传统企业应用、Web 应用。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">表示层（UI） -&amp;gt; 业务逻辑层 -&amp;gt; 数据访问层 -&amp;gt; 数据库
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="2-微服务架构microservices-architecture">2. 微服务架构（Microservices Architecture）
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>定义&lt;/strong>：将系统拆分为小型、独立的服务，每个服务专注于单一功能，通过 API 通信。&lt;/li>
&lt;li>&lt;strong>优点&lt;/strong>：高扩展性、独立部署、团队自治。&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>：分布式系统复杂性、部署和监控成本高。&lt;/li>
&lt;li>&lt;strong>适用场景&lt;/strong>：大型分布式系统、快速迭代的产品。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：Netflix、Amazon 的服务架构。&lt;/li>
&lt;/ul>
&lt;h3 id="3-事件驱动架构event-driven-architecture">3. 事件驱动架构（Event-Driven Architecture）
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>定义&lt;/strong>：组件通过事件（消息）异步通信，事件生产者与消费者解耦。&lt;/li>
&lt;li>&lt;strong>优点&lt;/strong>：高响应性、松耦合、易于扩展。&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>：事件追踪和调试复杂。&lt;/li>
&lt;li>&lt;strong>适用场景&lt;/strong>：实时处理系统、物联网。&lt;/li>
&lt;li>&lt;strong>示例&lt;/strong>：Kafka 或 RabbitMQ 驱动的系统。&lt;/li>
&lt;/ul>
&lt;h3 id="4-领域驱动设计ddd-domain-driven-design">4. 领域驱动设计（DDD, Domain-Driven Design）
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>定义&lt;/strong>：以业务领域为核心，设计模型和架构，强调领域模型的清晰表达。&lt;/li>
&lt;li>&lt;strong>优点&lt;/strong>：贴近业务需求，易于维护。&lt;/li>
&lt;li>&lt;strong>缺点&lt;/strong>：学习曲线陡峭，初期投入高。&lt;/li>
&lt;li>&lt;strong>适用场景&lt;/strong>：复杂业务系统。&lt;/li>
&lt;/ul>
&lt;h3 id="5-其他模式">5. 其他模式
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>模型-视图-控制器（MVC（Model-View-Controller）&lt;/strong>：分离数据、界面和控制逻辑，常见于 Web 开发。&lt;/li>
&lt;li>&lt;strong>CQRS（Command Query Responsibility Segregation）&lt;/strong>：读写分离，优化性能和扩展性。&lt;/li>
&lt;li>&lt;strong>Serverless 架构&lt;/strong>：基于云函数，按需运行，降低运维成本。&lt;/li>
&lt;li>管道-过滤器架构 (Pipe and Filter Architecture): 将数据处理过程分解为一系列独立的过滤器，数据通过管道在过滤器之间流动。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第四部分架构设计流程">第四部分：架构设计流程
&lt;/h2>&lt;h3 id="1-需求分析">1. 需求分析
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>功能需求&lt;/strong>：明确系统需要实现的功能。&lt;/li>
&lt;li>&lt;strong>非功能需求&lt;/strong>：性能、可靠性、可扩展性、安全性等。&lt;/li>
&lt;li>&lt;strong>约束条件&lt;/strong>：预算、技术栈、团队能力等。&lt;/li>
&lt;/ul>
&lt;h3 id="2-系统分解">2. 系统分解
&lt;/h3>&lt;ul>
&lt;li>将系统划分为模块或服务。&lt;/li>
&lt;li>使用 UML 图（如类图、序列图）或 C4 模型描述系统结构。&lt;/li>
&lt;li>定义模块间的接口和通信方式。&lt;/li>
&lt;/ul>
&lt;h3 id="3-技术选型">3. 技术选型
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>编程语言&lt;/strong>：根据团队经验和项目需求选择（如 Java、Python、Go）。&lt;/li>
&lt;li>&lt;strong>框架&lt;/strong>：选择合适的框架（如 Spring、Django）。&lt;/li>
&lt;li>&lt;strong>数据库&lt;/strong>：关系型（MySQL）还是非关系型（MongoDB）？&lt;/li>
&lt;li>&lt;strong>基础设施&lt;/strong>：云服务（AWS、Azure）还是本地部署？&lt;/li>
&lt;/ul>
&lt;h3 id="4-架构验证">4. 架构验证
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>原型验证&lt;/strong>：开发最小可行原型（MVP）测试架构可行性。&lt;/li>
&lt;li>&lt;strong>性能测试&lt;/strong>：模拟高负载场景，验证系统性能。&lt;/li>
&lt;li>&lt;strong>安全评估&lt;/strong>：检查潜在安全漏洞。&lt;/li>
&lt;/ul>
&lt;h3 id="5-文档化">5. 文档化
&lt;/h3>&lt;ul>
&lt;li>编写架构设计文档，包含：
&lt;ul>
&lt;li>系统概述&lt;/li>
&lt;li>架构图（C4 模型、UML 图）&lt;/li>
&lt;li>技术选型理由&lt;/li>
&lt;li>模块职责和接口定义&lt;/li>
&lt;li>部署和维护指南&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第五部分工具与技术">第五部分：工具与技术
&lt;/h2>&lt;h3 id="1-建模工具">1. 建模工具
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>UML 工具&lt;/strong>：Enterprise Architect、StarUML。&lt;/li>
&lt;li>&lt;strong>C4 模型工具&lt;/strong>：Structurizr、Draw.io。&lt;/li>
&lt;li>&lt;strong>流程图工具&lt;/strong>：Lucidchart、Visio。&lt;/li>
&lt;/ul>
&lt;h3 id="2-架构描述语言">2. 架构描述语言
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Archimate&lt;/strong>：企业架构建模语言。&lt;/li>
&lt;li>&lt;strong>ADL（Architecture Description Language）&lt;/strong>：用于形式化描述架构。&lt;/li>
&lt;/ul>
&lt;h3 id="3-部署与监控">3. 部署与监控
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>容器化&lt;/strong>：Docker、Kubernetes。&lt;/li>
&lt;li>&lt;strong>CI/CD&lt;/strong>：Jenkins、GitHub Actions。&lt;/li>
&lt;li>&lt;strong>监控&lt;/strong>：Prometheus、Grafana。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第六部分案例分析">第六部分：案例分析
&lt;/h2>&lt;h3 id="案例设计一个电商平台架构">案例：设计一个电商平台架构
&lt;/h3>&lt;h4 id="需求">需求
&lt;/h4>&lt;ul>
&lt;li>支持用户注册、商品浏览、订单处理、支付。&lt;/li>
&lt;li>高并发（双11促销）。&lt;/li>
&lt;li>可扩展以支持新功能（如推荐系统）。&lt;/li>
&lt;/ul>
&lt;h4 id="架构设计">架构设计
&lt;/h4>&lt;ul>
&lt;li>&lt;strong>模式&lt;/strong>：微服务架构 + 事件驱动。&lt;/li>
&lt;li>&lt;strong>服务拆分&lt;/strong>：
&lt;ul>
&lt;li>用户服务：管理用户注册、登录。&lt;/li>
&lt;li>商品服务：商品目录、库存管理。&lt;/li>
&lt;li>订单服务：订单创建、状态管理。&lt;/li>
&lt;li>支付服务：对接支付网关。&lt;/li>
&lt;li>推荐服务：个性化推荐。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>技术栈&lt;/strong>：
&lt;ul>
&lt;li>后端：Spring Boot（Java）。&lt;/li>
&lt;li>数据库：MySQL（订单、用户）、MongoDB（商品目录）。&lt;/li>
&lt;li>消息队列：Kafka（异步事件处理）。&lt;/li>
&lt;li>缓存：Redis（高频数据）。&lt;/li>
&lt;li>部署：Kubernetes + AWS。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>架构图&lt;/strong>（C4 模型简化版）：
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">用户 -&amp;gt; API 网关 -&amp;gt; [用户服务, 商品服务, 订单服务, 支付服务]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">订单服务 -&amp;gt; Kafka -&amp;gt; 推荐服务
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">所有服务 -&amp;gt; MySQL/MongoDB/Redis
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h4 id="验证">验证
&lt;/h4>&lt;ul>
&lt;li>性能测试：模拟 10 万并发用户，确保响应时间 &amp;lt; 200ms。&lt;/li>
&lt;li>安全：使用 OAuth2 认证，加密支付数据。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第七部分常见挑战与解决方案">第七部分：常见挑战与解决方案
&lt;/h2>&lt;h3 id="1-可扩展性">1. 可扩展性
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>问题&lt;/strong>：系统无法应对用户增长。&lt;/li>
&lt;li>&lt;strong>解决方案&lt;/strong>：使用微服务、分布式数据库、负载均衡。&lt;/li>
&lt;/ul>
&lt;h3 id="2-性能瓶颈">2. 性能瓶颈
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>问题&lt;/strong>：响应时间过长。&lt;/li>
&lt;li>&lt;strong>解决方案&lt;/strong>：引入缓存（Redis）、CDN，优化数据库查询。&lt;/li>
&lt;/ul>
&lt;h3 id="3-维护复杂性">3. 维护复杂性
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>问题&lt;/strong>：代码和架构过于复杂。&lt;/li>
&lt;li>&lt;strong>解决方案&lt;/strong>：遵循 KISS 和 DRY 原则，定期重构。&lt;/li>
&lt;/ul>
&lt;h3 id="4-分布式系统一致性">4. 分布式系统一致性
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>问题&lt;/strong>：数据一致性难以保证。&lt;/li>
&lt;li>&lt;strong>解决方案&lt;/strong>：使用分布式事务（如 Saga 模式）或最终一致性。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第八部分学习资源与进阶">第八部分：学习资源与进阶
&lt;/h2>&lt;h3 id="1-推荐书籍">1. 推荐书籍
&lt;/h3>&lt;ul>
&lt;li>《软件架构模式》（Mark Richards）&lt;/li>
&lt;li>《领域驱动设计》（Eric Evans）&lt;/li>
&lt;li>《微服务架构设计模式》（Chris Richardson）&lt;/li>
&lt;/ul>
&lt;h3 id="2-在线课程">2. 在线课程
&lt;/h3>&lt;ul>
&lt;li>Coursera：软件架构与设计&lt;/li>
&lt;li>Udemy：微服务架构实战&lt;/li>
&lt;/ul>
&lt;h3 id="3-实践建议">3. 实践建议
&lt;/h3>&lt;ul>
&lt;li>参与开源项目，学习真实架构。&lt;/li>
&lt;li>设计小型项目（如博客系统、聊天应用）并优化架构。&lt;/li>
&lt;li>关注行业案例（如 Netflix、Uber 的架构分享）。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="总结">总结
&lt;/h2>&lt;p>软件架构设计是一门结合技术和业务的艺术。通过掌握架构原则、模式和流程，开发者可以设计出满足需求、易于维护的系统。持续学习和实践是成为优秀架构师的关键。&lt;/p></description></item><item><title>作图参考</title><link>https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/</link><pubDate>Tue, 25 Mar 2025 11:00:07 +0800</pubDate><guid>https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/</guid><description>&lt;img src="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index.png" alt="Featured image of post 作图参考" />&lt;h3 id="development-plan">Development Plan
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index.png"
width="1024"
height="680"
srcset="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index_hu5588503875579021818.png 480w, https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index_hu2250390569384563294.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="150"
data-flex-basis="361px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-1.png"
width="650"
height="795"
srcset="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-1_hu4212515713241032061.png 480w, https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-1_hu11156414769069659291.png 1024w"
loading="lazy"
class="gallery-image"
data-flex-grow="81"
data-flex-basis="196px"
>&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-2.png"
width="923"
height="2010"
srcset="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-2_hu6155732392404605850.png 480w, https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-2_hu18169186536504900669.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="45"
data-flex-basis="110px"
>&lt;/p>
&lt;h3 id="文档书写参考">文档书写参考
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-3.png"
width="456"
height="812"
srcset="https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-3_hu10972627496090840817.png 480w, https://www.zata.cc/p/%E4%BD%9C%E5%9B%BE%E5%8F%82%E8%80%83/images/index/index-3_hu4615913077414983618.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="56"
data-flex-basis="134px"
>&lt;/p></description></item><item><title>使用ai工具绘制原型图html并导入figma</title><link>https://www.zata.cc/p/%E4%BD%BF%E7%94%A8ai%E5%B7%A5%E5%85%B7%E7%BB%98%E5%88%B6%E5%8E%9F%E5%9E%8B%E5%9B%BEhtml%E5%B9%B6%E5%AF%BC%E5%85%A5figma/</link><pubDate>Mon, 10 Mar 2025 11:07:28 +0800</pubDate><guid>https://www.zata.cc/p/%E4%BD%BF%E7%94%A8ai%E5%B7%A5%E5%85%B7%E7%BB%98%E5%88%B6%E5%8E%9F%E5%9E%8B%E5%9B%BEhtml%E5%B9%B6%E5%AF%BC%E5%85%A5figma/</guid><description>&lt;img src="https://www.zata.cc/p/%E4%BD%BF%E7%94%A8ai%E5%B7%A5%E5%85%B7%E7%BB%98%E5%88%B6%E5%8E%9F%E5%9E%8B%E5%9B%BEhtml%E5%B9%B6%E5%AF%BC%E5%85%A5figma/images/index/index.png" alt="Featured image of post 使用ai工具绘制原型图html并导入figma" />&lt;div style="position:relative; padding-bottom:75%; width:100%; height:0">
&lt;iframe
src="//player.bilibili.com/player.html?bvid=BV1tXRAYiEYR&amp;page=1&amp;as_wide=1&amp;high_quality=1"
scrolling="no"
border="0"
frameborder="no"
framespacing="0"
allowfullscreen="true"
style="position:absolute; height: 100%; width: 100%;"
>
&lt;/iframe>
&lt;/div></description></item><item><title>数据流图</title><link>https://www.zata.cc/p/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/</link><pubDate>Mon, 24 Feb 2025 00:00:00 +0000</pubDate><guid>https://www.zata.cc/p/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/</guid><description>&lt;h1 id="数据流图">数据流图
&lt;/h1>&lt;p>&lt;img src="https://www.zata.cc/p/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/images/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/image.png"
width="750"
height="368"
srcset="https://www.zata.cc/p/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/images/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/image_hu4619770938531770692.png 480w, https://www.zata.cc/p/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/images/%E6%95%B0%E6%8D%AE%E6%B5%81%E5%9B%BE/image_hu5875801080698908303.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="203"
data-flex-basis="489px"
>&lt;/p></description></item><item><title>类图</title><link>https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/</link><pubDate>Thu, 20 Feb 2025 00:00:00 +0000</pubDate><guid>https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/</guid><description>&lt;h1 id="类图">类图
&lt;/h1>&lt;h2 id="类图的概念笔记">类图的概念笔记
&lt;/h2>&lt;h3 id="1-什么是类图">1. 什么是类图？
&lt;/h3>&lt;ul>
&lt;li>类图是 UML（统一建模语言）中最常用的一种静态结构图。&lt;/li>
&lt;li>作用：展示系统中类的结构、属性、方法以及类与类之间的关系。&lt;/li>
&lt;li>应用场景：软件设计、系统建模，帮助开发者理解和规划代码结构。&lt;/li>
&lt;/ul>
&lt;h3 id="2-类的基本组成">2. 类的基本组成
&lt;/h3>&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image.png"
width="379"
height="256"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image_hu13235966263381512116.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image_hu3402905089824024269.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="148"
data-flex-basis="355px"
>&lt;/p>
&lt;p>一个类通常用一个矩形框表示，分为三部分：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>顶部：类名&lt;/strong>
&lt;ul>
&lt;li>写类的名称（通常首字母大写）。&lt;/li>
&lt;li>如果是抽象类，类名用&lt;em>斜体&lt;/em>表示。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>中间：属性&lt;/strong>
&lt;ul>
&lt;li>
&lt;p>表示类的特性或数据（成员变量）。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>格式：&lt;code>[可见性] 属性名 : 类型 [默认值]&lt;/code>&lt;/p>
&lt;ul>
&lt;li>可见性：&lt;code>+&lt;/code>（public）、&lt;code>-&lt;/code>（private）、&lt;code>#&lt;/code>（protected）、&lt;code>~&lt;/code>（package）。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-1.png"
width="285"
height="196"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-1_hu4677531634427514055.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-1_hu6430094819785333916.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="145"
data-flex-basis="348px"
>&lt;/p>
&lt;ul>
&lt;li>示例：&lt;code>-age : int = 18&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>底部：方法（操作）&lt;/strong>
&lt;ul>
&lt;li>表示类的行为或功能（成员函数）。&lt;/li>
&lt;li>格式：&lt;code>[可见性] 方法名(参数) : 返回类型&lt;/code>
&lt;ul>
&lt;li>示例：&lt;code>+getAge() : int&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="3-类与类之间的关系">3. 类与类之间的关系
&lt;/h3>&lt;p>来源：https://juejin.cn/post/6844903893327937550&lt;/p>
&lt;p>类图的核心是描述类之间的关系，常见的有以下几种：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-3.png"
width="904"
height="872"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-3_hu13250733071156308290.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-3_hu13928915357400703694.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="103"
data-flex-basis="248px"
>&lt;/p>
&lt;ol>
&lt;li>继承关系（Generalization/extends）&lt;/li>
&lt;/ol>
&lt;p>继承关系也叫泛化关系，指的是一个类（称为子类、子接口）继承另外的一个类（称为父类、父接口）的功能，并可以增加它自己的新功能的能力，继承是类与类或者接口与接口之间最常见的关系。
继承用实线空心箭头表示，由子类指向父类。
下面写两个子类，Fish和Cat分别继承自Animal。
&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-4.png"
width="756"
height="961"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-4_hu4613961026339582353.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-4_hu15769347914199156650.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="78"
data-flex-basis="188px"
>&lt;/p>
&lt;ol start="2">
&lt;li>实现关系（implements）&lt;/li>
&lt;/ol>
&lt;p>指的是一个class类实现interface接口（可以是多个）的功能；实现是类与接口之间最常见的关系；在Java中此类关系通过关键字implements明确标识，在iOS中我将其理解成代理的实现。
写一个洋娃娃类Doll，该类遵循了ToyAction协议，实现了玩具移动的方法。
&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-5.png"
width="756"
height="835"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-5_hu3396595097139593337.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-5_hu11297709041384878193.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="90"
data-flex-basis="217px"
>&lt;/p>
&lt;ol start="3">
&lt;li>依赖关系（Dependency）&lt;/li>
&lt;/ol>
&lt;p>可以简单的理解，就是一个类A使用到了另一个类B，而这种使用关系是具有偶然性的、、临时性的、非常弱的，但是B类的变化会影响到A；比如某人要过河，需要借用一条船，此时人与船之间的关系就是依赖；表现在代码层面，为类B作为参数被类A在某个method方法中使用。
在我们的上述代码中Cat的playToy方法中参数引用了Doll，因此他们是依赖关系。
&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-6.png"
width="874"
height="266"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-6_hu11704694191483919447.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-6_hu5758575312181192172.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="328"
data-flex-basis="788px"
>&lt;/p>
&lt;ol start="4">
&lt;li>关联关系（Association）&lt;/li>
&lt;/ol>
&lt;p>他体现的是两个类、或者类与接口之间语义级别的一种强依赖关系，比如我和我的朋友；这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的，一般是长期性的，而且双方的关系一般是平等的、关联可以是单向、双向的；表现在代码层面，为被关联类B以类属性的形式出现在关联类A中，也可能是关联类A引用了一个类型为被关联类B的全局变量；
写一个Person类，他拥有一个宠物猫，他们之间的关系是关联。
&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-7.png"
width="756"
height="686"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-7_hu11272320388337830763.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-7_hu15326361838124087092.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="110"
data-flex-basis="264px"
>&lt;/p>
&lt;ol start="5">
&lt;li>聚合关系（Aggregation）
聚合是关联关系的一种特例，他体现的是整体与部分、拥有的关系，即has-a的关系，此时整体与部分之间是可分离的，他们可以具有各自的生命周期，部分可以属于多个整体对象，也可以为多个整体对象共享；比如计算机与CPU、公司与员工的关系等；表现在代码层面，和关联关系是一致的，只能从语义级别来区分；&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-8.png"
width="756"
height="677"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-8_hu6686645750057382010.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-8_hu14660679097470859118.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="111"
data-flex-basis="268px"
>&lt;/p>
&lt;ol start="6">
&lt;li>组合关系（Composition）
组合也是关联关系的一种特例，他体现的是一种contains-a的关系，这种关系比聚合更强，也称为强聚合；他同样体现整体与部分间的关系，但此时整体与部分是不可分的，整体的生命周期结束也就意味着部分的生命周期结束；比如你和你的大脑；表现在代码层面，和关联关系是一致的，只能从语义级别来区分；
上述代码中的Person拥有Head，并且这个整体和部分是不可分割的。&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-9.png"
width="766"
height="224"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-9_hu844725690583967431.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-9_hu15078543426319998628.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="341"
data-flex-basis="820px"
>&lt;/p>
&lt;p>最后来看看这个例子中的整体关系：&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-10.png"
width="1726"
height="944"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-10_hu17240506101887387161.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-10_hu4679307890386820978.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="182"
data-flex-basis="438px"
>&lt;/p>
&lt;p>其实理解了之后我们发现还是很简单的，学会了之后就可以投入实践中了，举一个简单第三方库的类图例子，下图是Masonry的类图整理，可以看到项目结构很清晰的展示了出来。&lt;/p>
&lt;p>&lt;img src="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-11.png"
width="1416"
height="759"
srcset="https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-11_hu10080896141775018548.png 480w, https://www.zata.cc/p/%E7%B1%BB%E5%9B%BE/images/%E7%B1%BB%E5%9B%BE/image-11_hu15081855724984045319.png 1024w"
loading="lazy"
alt="alt text"
class="gallery-image"
data-flex-grow="186"
data-flex-basis="447px"
>&lt;/p>
&lt;h3 id="4-类图的符号速查">4. 类图的符号速查
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>矩形框&lt;/strong>：类&lt;/li>
&lt;li>&lt;strong>实线&lt;/strong>：关联&lt;/li>
&lt;li>&lt;strong>空心菱形+实线&lt;/strong>：聚合&lt;/li>
&lt;li>&lt;strong>实心菱形+实线&lt;/strong>：组合&lt;/li>
&lt;li>&lt;strong>空心三角+实线&lt;/strong>：继承&lt;/li>
&lt;li>&lt;strong>空心三角+虚线&lt;/strong>：实现&lt;/li>
&lt;li>&lt;strong>虚线箭头&lt;/strong>：依赖&lt;/li>
&lt;/ul></description></item></channel></rss>