【DDD】学习笔记-UML 与彩色建模

news2024/11/24 8:52:37

如果某个领域已经形成了稳定的分析模式,在设计该领域的分析模型时,这些模式就可以提供有价值的参考。可惜,分析模式需要有人来总结和提炼,最好的分析模式提炼者需要兼具领域知识和软件建模能力。很早以前,Martin Fowler 扮演了这一角色,他贡献了《分析模式》这本经典的著作。这是公开的分析模式。囿于领域知识的壁垒以及商业竞争的压力,各个领域或许已经通过数年的演化获得了稳定的分析模式,却只能像传说那样仅限于口传而不见诸于文字。这不能不说是一种遗憾。软件的发展是靠着各种重用才变得如此快速高效,领域模型却因为缺乏可以重用的模式,变得有些举步维艰。

如果没有这种可以直接参考甚至重用的模式,那就必须回到方法与过程上来。分析模式将模型分为知识级和操作级,就是一种建模方法,只可惜这种方法太过艰深晦涩,不曾提供清晰直观的建模思路。名词动词法又过于简单而随意,欠缺精准,属于分析建模的初级阶段。倘若要面向一个非常复杂的领域,各种领域概念如混乱的思绪一般纷至沓来,就需要运用更加系统更有条理的建模方法。

Peter Coad 等人提出的彩色 UML(Color UML)应运而生。个人认为,它为领域建模做出了两大贡献。

第一个贡献是它定义了四种与领域无关的模型架构型(Archetype):时标架构型、角色架构型、描述架构型和参与方—地点—物品架构型。这四种架构型基本上涵盖了所有能够表达领域概念的模型对象。在领域建模时,可以利用这些架构型提供的特征描述,帮助我们识别对象。这恰好是领域驱动设计缺失的内容。

第二个贡献是它创新地引入了颜色标记对领域模型进行可视化展示,丰富了模型的表现力,而这种彩色建模的手段也能够有效地促进领域专家与开发团队之间的交流。当颜色成为模型对象的一种重要编码时,结合它归纳的四种架构型,就能够清晰传递各个对象在业务场景中扮演的角色,理清它们之间的关系。倘若再摆脱 UML 对模型的约束,就可以用各种颜色的即时贴来表示领域模型,将彩色 UML 的思想运用到可视化协作的建模过程中。

彩色 UML 的架构型

色彩是表象,架构型才是彩色建模方法的重心。若要学会运用彩色建模,就需要明确这些架构型的特征,方才可以依照这些特征在浩如烟海的领域语言中按图索骥。

时标架构型

时标架构型(Moment-interval Archetype)的核心要素是时刻或时段。《彩色 UML 建模》一书这样总结时标架构型:

它代表了出于商业和法律上的原因,我们需要处理并跟踪的某些事情,这些事情是在某个时刻或某一段时间内发生的。……(它)寻找的是问题域中具有重要意义的时刻或时段。

显然,时刻或时段是时标架构型的特征属性。在这个时刻或时段,有某件事情发生了,而这件事情对于我们要处理的领域而言,具有重要意义。如果缺少对它的记录,就会影响到商业的运营和管理,或者引起法律上的纠纷。一言以蔽之,时标架构型的核心要素包括:时刻/时段重大事件,二者缺一不可。例如,一次销售发生在某一个时刻,如果缺少对销售的记录,会影响企业的收支估算,影响销售人员的提成收益。一次租赁从登记入住到租约期满,发生在一个时段,如果缺少对租赁的记录,会导致租赁双方的法律合同纠纷。

时刻或时段是业务含义的属性,而非技术因素。例如,我们不能将数据记录的创建或修改时间戳看作时标架构型的时标属性。即使是业务含义的属性,也不能说明具有时标属性的对象就一定是时标型对象。例如,一个员工具有出生日期属性,但员工的诞生对于一个企业而言,没有任何意义。如果要更好地管理员工,更为关注的是员工的入职日期(OnBoardingDate)。那么,此时的员工会是时标型对象吗?——不是!因为员工这个对象并非入职日期这个时刻发生的事件,入职 OnBoarding 对象才是。

因此,寻找时标型对象就是要从业务流程中找到任何一个重大的时刻或时段,然后再来分析在这个时刻或时段到底发生了什么,发生的事情结果就是我们要寻找的建模目标。例如,在 2019 年 6 月 7 日 9 时……

  • 考生张华踏入了高考语文的考场:发生了一次考试(Exam)
  • 学生刘烨在图书馆借阅了一本《领域驱动设计》:产生了一次借阅(Borrowing)
  • 客户李明取走了一笔 3000 元人民币的款项:产生了一次取款交易(Transaction)
  • 交警李飞处理了一起交通违法事项:开具了一次罚单(Ticket)
  • 买家唐嫣在淘宝购买了一支护手霜:提交了一次订单(Order)

以上事件都发生在 2019 年 6 月 7 日 9 时,产生的记录在各自系统中都具有不可缺失的重要意义。缺少考生考试记录,会影响考生成绩;少了一次借阅,可能丢失一本书;交易记录如果存储失败,会影响银行的对账;少记录一次处罚,会给公务人员中饱私囊的机会;订单如果找不到了,买家和卖家就会产生纠纷。显然,这些时标型对象都会影响到运营和管理。

角色架构型

角色架构型(Role Archetype)是一种参与的方式,它由参与方、地点或物品来承担。角色就好像是参与方—地点—物品模型对象戴的帽子,这些对象在不同的业务场景中扮演了不同的角色,参与了业务的协作。因此,角色架构型接近于面向对象设计中的角色接口,参与方—地点—物品作为对象实现了这些角色接口。例如在银行的转账场景中,账户 Account 是参与方对象,它扮演的角色是转出方 SourceAccount 和转入方 DestinationAccount 角色。

除了参与协作,角色架构型有时候也表达了某种关系。例如,角色对象 ProductOrdered 体现了订单项与产品之间的关系,在订单场景中,它扮演了订购产品的角色;角色对象 MaterialShipped 体现了配送单与物料之间的关系,在配送场景中,它扮演了已发货物料的角色。

如果扮演角色的对象是参与方,则角色架构型往往代表业务领域中形形色色的职业角色,如销售人员 SalePerson、供应商 Supplier、收银员 Cashier、团队成员 TeamMember、订单拥有者 OrderOwner。

描述架构型

Peter Coad 认为描述架构型(Description Archetype)是一种类似分类目录(catalog-entry-like)的描述。这个定义比较含糊。我的理解是描述对象包含的属性体现了分类的特征,是对描述目标对象的扩展与增强。例如一本书的属性包括书的书名、作者、出版社、出版日期、ISBN 号与价格,而书的推荐语、作者简介、版权信息与目录就是对书的扩展描述,且这些属性也说明了这是一本书,而非家电、化妆品、衣物等类别。

虽然 Peter Coad 没有明确指出描述架构型是针对哪一种架构型的描述,但通常可以认为是针对参与方—地点—物品架构型对象的增强。

参与方—地点—物品架构型

参与方—地点—物品架构型(Party-place-thing Archetype)直接说明了三种类型的模型对象,即参与方、地点与物品,其中参与方指代人或组织。由于参与方、地点与物品的英文首字母分别为 PPT,我们往往将其戏称为 PPT 对象。

与时标型对象相似,PPT 对象具有非常明显的特征。在需求描述中,只要发现领域概念与人、组织机构、地点或物品相关,就可以识别为 PPT 对象。例如雇员 Employee 和买家 Buyer 可以作为员工管理场景和电商购买场景的参与方。组织机构也可以作为参与方,如购买团体保险的组织 Organization、物流快递的承运商 Carrier。物流快递的配送站 DistributionStation、通信领域中的基站 NodeB 则体现了地点的概念。体现物品概念的模型对象更为常见,例如物料 Material、商品 Product、信用卡 CreditCard 以及前面提到的书 Book,都是物品对象。

注意:作为 PPT 构造型的组织机构以及作为角色构造型的角色,与权限认证管理场景中的组织机构与角色属于两个不同的模型概念。二者的区分可以从限界上下文的角度来考虑。例如,团体保险的组织 Organization 是客户上下文中的领域对象,角色对象 SalePerson 是销售上下文中的领域对象,而权限认证管理中的 Department、Role 等概念,则都属于权限认证上下文。

架构型对领域分析建模的启发

彩色 UML 定义的这四种架构型并不是要限制我们的模型对象,而是希望通过提炼模型对象的特征来帮助建模人员。例如,时标型对象的特征是时刻与时段,这就促使我们去需求描述中寻找那些具有时刻时段特性的模型对象。PPT 对象归纳了参与方、地点与物品这三种类型,就能启发建模人员去寻找包括人和组织机构的参与方、地点和物品。角色架构型的特征体现为业务场景的参与角色,在分析业务场景时,我们就会有意识地识别各种模型对象所承担的角色(帽子)到底是什么。描述架构型作为 PPT 对象的补充与扩展,既可以让我们设计出粒度合理的 PPT 对象,又不至于丢失一些非核心但却能起到补充作用的领域对象。

Peter Coad 等人认为:由这四种架构型构成了领域无关的组件。在分析模型中,我们也可以通过显式地标记架构型或者通过颜色来体现这些架构型对象,但在领域设计模型和领域实现模型中,我们其实并不是特别看重领域对象到底是什么架构型。换言之,彩色 UML 定义的四种架构型并非领域建模的目标,而是领域分析建模活动中的一种方法。在领域分析建模活动中,不必执着或拘泥于确定该模型对象到底属于哪一种架构型。只要你识别出了合理的领域对象,就达到目标了。如果总是花费时间纠结它到底是 PPT 架构型还是时标架构型,就会让你忘记什么才是建模的初衷,舍本逐末。

彩色 UML 的建模过程

彩色 UML 并没有给出识别领域模型对象的分析过程。它假定我们在寻找到一个类时,需要利用一个检查清单来确定它属于什么架构型,从而确定该类在 UML 类图与时序图中的颜色。这个检查清单如下:

  1. 它是时刻或时段,是出于业务原因或法律原因,是系统需要追踪的东西吗?如果是这样,那么它是粉红色的时刻时段。
  2. 否则,它是一个角色吗?如果是这样,那么它是黄色的角色。
  3. 否则,它是一个分类目录条目似的描述,包含了一组可以反复应用的值吗?如果是这样,那么它是蓝色的描述。
  4. 否则,它就是参与方—地点—物品。它是绿色的参与方—地点—物品(绿色是默认色,如果不是粉红色、黄色或蓝色,它就是绿色)。

这是针对单个模型对象的检查过程。我们识别出一个模型对象,然后讨论它是什么架构型,确定了架构型后,在 UML 类图中绘制出来,并以对应的颜色作为背景色,然后继续识别下一个模型对象。——这是我们希望看到的建模过程吗?

我认为这种方式实际上降低了彩色 UML 的价值,将它沦落为一种具有彩色标记的 UML 表示法。采用这种方式建模,意味着在运用彩色 UML 之前,我们已经识别出了各种领域模型对象,彩色 UML 的作用仅仅在于确定它们的架构型,然后为其涂上美丽的颜色。可是,如果已经有了这些领域模型对象,我们还要彩色 UML 干什么呢?难道彩色 UML 的目的只是为了给类涂上颜色,让 UML 变得更加好看吗?

领域建模过程显然不是这样的!彩色 UML 带来的价值绝不仅止于此,可惜它的创造者 Peter Coad 等人反倒是低估了这一方法。这不能不说是一种遗憾。通读《彩色 UML 建模》全书,我认为作者希望仿照 Martin Fowler 的《分析模式》,以彩色 UML 的形式为领域建模活动提供可以参考的领域模型(即书中列出的 61 个领域相关的组件)。因此,它过于强调获得的领域模型,却不曾清晰地表达是如何获得这些领域模型的。吊诡的事情在于,其实后者才是领域建模的关键,也是领域建模的难点所在。

我们可以看看该书第 3 章给出的案例“产品销售管理”,了解它的领域模型在彩色 UML 的框架下是如何得来的,即可印证我的评价是否中肯。书中讨论的产品销售管理主要针对客户开发票与支付的业务功能。书中分析该业务场景,获得如下业务步骤:

  • 定义产品类型和产品
  • 销售给客户
  • 发送产品
  • 给客户开发票
  • 记录产品的支付,追踪并解决交付问题报告
  • 达成协议并完成评估

产品销售管理还要与库存管理交互,需要在发送产品之后从库存中扣除数量;同时,还需要与会计管理交互,针对发票金额进行过账。

在描述了产品销售管理的业务背景与关联系统之后,书中直接给出了如下时标型对象。至于它们是如何获得的,书中完全不曾提及:

  • 产品价格(ProductPrice)
  • 对客户的销售(SaleToCustomer)
  • 发货给客户(ShipmentToCustomer)
  • 交付给客户(DeliveryToCustomer)
  • 交付问题报告(DeliveryProblemReport)
  • 给客户开发票(InvoiceToCustomer)
  • 折扣协议(DiscountAgreement)
  • 佣金协议(CommissionAgreement)
  • 费用和开销分配(CostAndOverheadAllocation)
  • 市场调研(MarketingStudy)
  • 销售预测(SaleForcast)
  • 地理区域指派(GeographicRegionAssignment)

下图是这些时标型对象之间的关系:

img

接下来,作者摘取了一个交互场景“计算销售代表的直接佣金”,以此说明四种架构型对象之间的交互关系。书中这样描述:

消息发送者要求黄色的“销售代表”计算它的佣金,即来自于它们自己的销售的佣金(称为“直接”佣金)。“销售代表”对象要求它的每个粉红色的“销售”构建一份“产品销售明细”列表。接下来,“销售代表”对象要求它的每个粉红色的“佣金”对象计算直接佣金。然后,“佣金”对象将它的产品描述和数量与销售明细进行匹配,寻找有效的匹配,再计算产品销售的佣金。某些“佣金”对象可能没有链接到“产品描述”,在这种情况下,佣金适用于所有的产品销售明细。最后,“销售代表”将结果返回给消息发送者。

这个交互的时序图如下所示:

58906585.png

在“计算销售代表的直接佣金”交互场景中,真正对外的交互起点其实是黄色的角色对象:销售代表 SalesRep。因为需要计算销售的佣金,就需要获得销售明细与佣金协议,故而引入了两个时标型对象 SaleToCustomer 与 CommissionAggrement。为了支持佣金计算的功能,佣金自身也需要提供明细信息,于是得到了 CommissionAgreementDetail 对象。注意,这个对象并非描述对象,而是一个时标型对象。

接下来,作者就开始针对产品组件进行进一步的模型细化工作。在这个过程中,作者讨论了 PPT 对象与描述对象之间的差异:

绿色的“产品”是业务所销售的东西,是可以单独标识的(它有序列号),是必须单独追踪的。如果一件产品不是可以单独标识的,您就不需要一个绿色的物品;相反,您可以用带数量的、类似产品目录项的蓝色描述。

这说明区分 PPT 对象与描述对象的一个重要特征是看它是否需要单独标识。这与领域驱动设计区分实体和值对象有着异曲同工之妙。

这里虽然提到产品需要“单独追踪”,但由于它没有时标特性,因而被建模为 PPT 对象;与之相反,产品价格则是时标型对象,因为它的数量和计价单位适用于一个时段。针对产品价格的建模,作者给出了非常具有参考价值的评述,有利于我们理解时标型对象的特征:

对于价格,你可以有几种建模选择。您可以将它作为绿色“产品”的一个属性(例如,红色法拉利的价格,岿然不动的价格!),或者是蓝色的描述(例如,某个尺寸的 Snickers 巧克力棒的价格)。但是,如果您希望追踪以往的价格(用于趋势分析),当前的价格(用于销售),以及未来的价格(用于计划将来的价格变更),那么您就需要将“产品价格”建模为一个粉红色的时刻时段。

在将产品价格建模为时标型对象时,还将它链接到了一个黄色的“定价人 Pricer”角色对象,该角色负责设定价格。产品作为 PPT 对象中的物品对象,在产品销售管理中,会因为销售的产生,而扮演“销售的产品 ProductBeingSold”这个角色,它实际体现了产品和销售之间的关系。因此,围绕着产品获得的彩色模型如下:

img

由于篇幅有限,我并没有将《彩色 UML 建模》书中的整个例子全部摘抄过来,否则,我就成了一名彻头彻尾的文抄公了。本节内容仅呈现了彩色 UML 的冰山一角,但结合该案例对建模过程的简述,大致可以总结出这种建模思想的不足之处:

  • 彩色 UML 以时标型对象为主要的建模核心,但对于如何寻找这些时标型对象,除了谈到它的特征之外,并没有给出清晰的思路。
  • 建模时需要结合具体的业务场景考虑各种架构型对象之间的交互,交互场景的发起者为“消息发送者”,但提供对外交互接口对象的构造型却并不确定,可以是这四种架构型中的任何一种。
  • 描述对象虽然是 PPT 对象的补充与增强,但它并不一定成为 PPT 对象的附庸,有时候甚至会直接暴露行为给“消息发送者”。
  • 彩色 UML 并没有限定这四种架构型对象之间的关系,彼此之间可以互相链接,没有明确统一的关系约束。
  • 除了确定时标型对象作为建模起点之外,并没有为其他架构型对象给出清晰的建模步骤。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1445615.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nodejs切换版本

sudo n 18.17.0 sudo n然后键盘上下选择

Vue核心基础6:Vue内置指令、自定义指令、生命周期

1 Vue中的内置指令 <script>const vm new Vue({el: #root,data: {n: 1,m: 100,name: Vue,str: <h3>你好</h3>}})</script> 1.1 v-text <div v-text"name"></div>1.2 v-html <div v-html"str"></div> …

SpringCloud-高级篇(二十)

下面我们研究MQ的延迟性问题 &#xff08;1&#xff09;初始死信交换机 死信交换机作用一方面可以向Public的异常交换机一样做异常消息的兜底方案&#xff0c;另一方面&#xff0c;可以处理一些超时消息&#xff0c;功能比较丰富一点 &#xff08;2&#xff09;TTL 上面学习…

Java基础:值传递和引用传递

Java在给方法传递参数时&#xff0c;有值传递和引用传递两种方式。 基本概念 值传递&#xff1a;传递对象的一个副本&#xff0c;即使副本被改变&#xff0c;也不会影响源对象&#xff0c;因为值传递的时候&#xff0c;实际上是将实参的值复制一份给形参。 引用传递&#xf…

猫头虎分享已解决Bug || ValueError: Data cardinality is ambiguous

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【Cocos入门】物理系统

物理引擎默认是关闭状态以节省资源开销。开启方法和之前的普通碰撞类似:cc.directorgetPhysicsManager().enabled true但有一个区别&#xff0c;物理引擎的开启必须放在onLoad函数内运行&#xff0c;否则不生效。 开启物理引擎后&#xff0c;游戏运行&#xff0c;会发现添加…

C++多态重难点

CSDN上已经有很多关于C多态方面的一些系统介绍了&#xff0c;但是我看了一下一些有关于多态问题的细节问题文章较少&#xff0c;因此我想要出一片文章重点讲一讲我认为比较重点且容易被遗忘的知识点&#xff0c;一些比较基本的知识这里就不过多赘述了&#xff0c;可以参考其他优…

controller-manager学习三部曲之二:源码学习

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 作为《controller-manager学习三部曲》系列的第二篇&#xff0c;前面通过shell脚本找到了程序的入口&#xff0c;接下来咱们来学习controller-mana…

第三百一十八回

文章目录 1. 概念介绍2. 使用方法2.1 本地缓冲2.2 服务器缓冲3. 示例代码4. 内容总结我们在上一章回中介绍了"如何让输入键盘不遮挡屏幕"相关的内容,本章回中将介绍如何有效地缓冲网络图片.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章回中介绍的…

ArcGIS学习(七)图片数据矢量化

ArcGIS学习(七)图片数据矢量化 通过上面几个任务的学习,大家应该已经掌握了ArcGIS的基础操作,并且学习了坐标系和地理数据库这两个非常重要且稍微难一些的专题。从这一任务开始,让我们进入到实战案例板块。 首先进入第一个案例一一图片数据矢量化。 我们在平时的工作学…

单片机学习笔记---AT24C02数据存储

目录 AT24C02数据存储 准备工作 代码讲解 I2C.c 模拟起始位置的时序 模拟发送一个字节的时序 模拟接收应答的时序 模拟接收一个字节的时序 模拟发送应答的时序 模拟结束位置的时序 I2C.h AT24C02.c 字节写&#xff1a;在WORD ADDRESS&#xff08;字地址&#xff…

探索Nginx:强大的开源Web服务器与反向代理

一、引言 随着互联网的飞速发展&#xff0c;Web服务器在现代技术架构中扮演着至关重要的角色。Nginx&#xff08;发音为“engine x”&#xff09;是一个高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。Nginx因其卓越的性能、稳定性和灵活性&…

汽车零部件制造业MES系统解决方案

一、​汽车零部件行业现状 随着全球汽车产业不断升级&#xff0c;汽车零部件市场竞争日趋激烈&#xff0c;从上游的钢铁、塑料、橡胶等生产到下游的主机厂配套制造&#xff0c;均已成为全球各国汽车制造大佬战略目标调整的焦点&#xff0c;其意欲在汽车零部件行业快速开疆扩土&…

C++内联函数深入讲解

用法&#xff1a; 在函数的返回值前面加上inline&#xff0c;例如&#xff1a; 作用&#xff1a; 内联函数的存在其实是为了解决c语言中一些问题&#xff0c;比如有一个频繁调用的小函数&#xff0c;每次调用都需要建立栈帧&#xff0c;压栈出栈&#xff0c;减少了效率&#xf…

分享86个鼠标特效,总有一款适合您

分享86个鼠标特效&#xff0c;总有一款适合您 86个鼠标特效下载链接&#xff1a;https://pan.baidu.com/s/12Y_iMqt-7-jyw46k62ySDg?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不…

PKI - 借助Nginx实现_客户端使用自签证书供服务端验证

文章目录 Pre概述在 Nginx 中实现客户端使用自签名证书供服务器验证1. 生成客户端密钥对2. 生成自签名客户端证书3. 配置 Nginx4. 重启 Nginx 修5. 验证 在浏览器中安装客户端证书以便进行访问 Pre PKI - 借助Nginx 实现Https 服务端单向认证、服务端客户端双向认证 PKI - 数…

【Java EE初阶十二】网络编程TCP/IP协议(一)

1. 网络编程 通过网络&#xff0c;让两个主机之间能够进行通信->就这样的通信来完成一定的功能&#xff0c;进行网络编程的时候&#xff0c;需要操作系统给咱们提供一组API&#xff0c;通过这些API来完成编程&#xff1b;API可以认为是应用层和传输层之间交互的路径&#xf…

轴角与旋转矩阵、欧拉角与旋转矩阵、四元数与旋转矩阵的转换

一、轴角转换成旋转矩阵 C实现 #include <iostream> #include <Eigen/Dense> #define _USE_MATH_DEFINES #include <math.h> using namespace std;int main() {double theta M_PI/2;//90度Eigen::Vector3d xyz(1, 0, 0);//x轴Eigen::AngleAxisd rotation_…

Linux nohup命令和

参考资料 linux后台运行nohup命令的使用及2>&1字符详解 目录 前期准备一. 基本语法二. 执行时不指定日志文件三. 执行后不想要日志文件四. nohup命令的执行与kill4.1 执行4.2 kill 前期准备 &#x1f4c4;handle_file.sh #!/bin/bashecho "文件复制开始..."…

精读《js 模块化发展》

1 引言 如今&#xff0c;Javascript 模块化规范非常方便、自然&#xff0c;但这个新规范仅执行了 2 年&#xff0c;就在 4 年前&#xff0c;js 的模块化还停留在运行时支持&#xff0c;10 年前&#xff0c;通过后端模版定义、注释定义模块依赖。对经历过来的人来说&#xff0c;…