StarUML类图实战:六种关系、箭头画法与代码生成

StarUML类图实战:六种关系、箭头画法与代码生成 类图这东西刚入行的时候我也觉得它有点学院派——画完就压箱底代码该乱还是乱。后来带过几个项目踩过几次需求评审时大家各说各话、接口对不上的坑之后我才真正把类图当成日常工具用起来。现在我最常用的组合就是 StarUML 画类图把领域模型的骨架先摆清楚再动键盘写代码。用 StarUML 画类图说白了就是解决一个问题把脑子里那套有哪些对象、它们之间是什么关系的模糊想法变成一张谁都能看懂、能拿去讨论、能反过来指导编码的图。这篇内容适合三类人刚学 UML 想找一款顺手上手工具的学生、写了几年代码但没系统整理过模型的开发者、以及需要给团队出一份结构说明的技术负责人。我会从工具选型、元素语义、箭头画法一路讲到完整实操把 StarUML 画类图这件事拆开揉碎顺带把类图箭头怎么区分IDEA 和 Eclipse 能不能直接生成类图五种关系到底差在哪这些高频疑问一并说透。1. 先想清楚这张类图画给谁看1.1 类图的三个真实使用场景很多人学 UML 的路径是反的先从语法开始背背完符号不知道用在哪儿。我建议先把场景理清楚语法反而会记得牢。类图在工程实践中主要出现在三种场合这三种场合对图的精度要求完全不同先分清属于哪一种能省掉大量无用功。第一种是设计阶段的骨架草图。这时候你手上只有需求文档需要把业务概念抽象成类明确模块边界。这张图不用画全所有 getter/setter重点是类的划分和核心关系。我一般会把它控制在 10 到 15 个类以内超出这个量级说明拆分粒度有问题。这个阶段画图的目的不是交付而是逼自己想清楚画到一半发现某个类被所有东西依赖那基本就是设计出问题了。第二种是代码 review 与重构前的现状梳理。接手一个老项目代码几万行先别急着改。用反向工程把关键包生成类图看一眼哪个类扇出特别大、有没有循环依赖、继承层次是不是深到离谱。这种图追求的是完整字段和方法都得出来因为它要承担审计功能。第三种是对外沟通文档。给产品、测试或者甲方讲系统结构时一张干净的类图比十页文字管用。这时候要狠心做减法把技术细节比如说连接池、缓存装饰器全部砍掉只保留业务概念。我在实际项目里最常干的蠢事就是把三种图混在一张上画结果做设计的人嫌不够细做沟通的人嫌太乱。提示动手前先给自己一句话——这张图是给我自己看的还是给别人看的。答案不同画法完全不同这不是偷懒是专业。1.2 StarUML、IDE 内置工具、Visio、PlantUML 怎么选工具没有绝对的好坏只有场景匹配度。我把常见的几类方案列出来对比一下你可以对着自己的需求挑。方案优势短板适合场景StarUMLUML 语义完整、支持代码正反向工程、导出格式全商业软件需正规授权大图性能一般正经画类图、需要多语言代码互转IDEA 内置 Diagrams零配置、直接读代码、实时反映依赖布局自动生成、可读性差、不适合手工设计快速看现有代码结构Eclipse 插件如 Papyrus与 IDE 集成、支持模型驱动开发插件生态零散、学习曲线陡已经重度依赖 Eclipse 的团队draw.io / Visio自由度高、人人都能打开无 UML 语义、改一处全靠手工一次性插图、汇报材料PlantUML纯文本、能进版本库、改起来快需要记语法、排版不可控代码仓库里长期维护的图我的实际组合是设计和对外沟通用 StarUML仓库里长期维护的图用 PlantUML临时看代码结构直接用 IDEA 的 Diagram。这么分工的理由很简单——StarUML 的语义模型是结构化的一个类改了名字所有引用它的关系线都会自动更新而 draw.io 这类纯绘图的工具做不到你得手工去找每一条线。至于Eclipse 怎么看类图如果你在 Eclipse 里装个 UML 编辑插件或者代码反向工程插件就能右键生成但体验确实不如 IDEA 顺滑。IDEA 里对着包或类按 CtrlAltU 出图CtrlAltShiftU 在新窗口打开再点一下 Show Dependencies 就能看到类之间的依赖连线。不过要提醒一句IDE 自动生成的图布局非常物理类一多就是一坨面条它适合看不适合交付。1.3 关于安装与授权的正经说明StarUML 是商业软件官方提供评估版本长期商用建议走正规渠道购买许可。我不建议去折腾来路不明的激活方式——一来这类文件本身可能是安全风险入口二来团队协作时许可证合规是件很严肃的事被审计到很麻烦。所以在这一步上我的态度很明确要长期用就买许可只是临时画两天的图评估版配合免费方案完全够用。如果你预算确实紧张免费的替代路线也有PlantUML 写文本生成图Modelio 做完整建模draw.io 满足轻量绘图。这些工具的画图思路和 StarUML 是相通的把本文的语义部分搞明白换工具只是熟悉一下菜单的事。安装本身没什么门槛从官网下载对应系统的安装包即可。装完之后建议第一件事是进扩展管理器按需装语言扩展——比如你要从 Java 代码反向生成类图就得装 Java 扩展要生成 Python 骨架就装 Python 扩展。这个扩展是后面做代码互转的前提很多人卡在找不到反向工程菜单百分之八十是没装扩展。2. 开工前的环境准备与工作区配置2.1 界面四块区域先搞明白谁管什么打开 StarUML 新建项目之后界面基本分成四块理解这四块的分工比背快捷键重要得多。左上角是模型浏览器Model Explorer这是整套工具的骨架。你建的所有包、类、接口、枚举都挂在这棵树上它是模型不是画出来的东西。中间是绘图区Diagram你看到的方框和连线是模型元素在这个视图里的呈现。右边是属性面板Properties选中任何元素后它的名称、可见性、类型、多重性都在这里改。最左边是工具箱Toolbox切换不同图类型时它显示的工具集不一样画类图时我们需要的是 Class Diagram 那一套。这里要建立一个关键认知StarUML 里模型和图是两回事。同一个类可以出现在多张图里你在类上加了字段所有引用它的图都会同步。这就是它比画图软件强的地方也是新手最容易忽略的地方——很多人习惯在画布上随手拖方块结果模型树里一堆无名元素后面做代码生成直接崩。2.2 一个项目该怎么组织包、类、图的层级关系我见过不少人的 StarUML 项目点开就是一颗平铺的树五十个类全挂在一个 Model 下面找都找不到。规范的做法是按业务模块建包Package类放在包里图也放在包里。具体操作在模型浏览器里右键根 Model选 Add Package命名成业务模块名比如order、user、payment。然后在包上右键Add Diagram Class Diagram 添加类图再在这个包里建类。这样做的收益很直接——当你后来要生成代码时包结构会直接映射成代码里的目录结构一步到位不用手工挪。还有一种组织结构是把设计图和现状图分开放。我在做重构项目时会建两个包一个叫as-is现状一个叫to-be目标两张图并排摆着看改造路径一眼就清楚了。这个习惯是从一次大型重构里学来的当时没有对比图全靠记忆结果改到一半发现漏了两个依赖。2.3 动手画之前建议先调这几个默认设置默认设置不影响画图的正确性但影响你画完之后的幸福指数。我每次装完都固定调这三处。第一是字体和字号。默认字号在大屏上偏小中文字体如果落到某个奇怪的字体上还会出现字重不均。建议在偏好设置里把默认字体换成系统里清晰的无衬线字体字号调到 12 到 14 之间。类图上的文字是给人读的读起来费劲的图等于白画。第二是网格吸附与对齐。画布上开启网格显示之后拖动类元素会自动吸附横平竖直的感觉立刻出来。类图丑不丑一大半取决于元素是否对齐、连线是否走直角。后面讲排版时我还会细说但基础设置先打开能少走弯路。第三是连线的默认走线样式。StarUML 的连线支持直线和折线两种走法折线Rectilinear在类图里几乎总是更好看因为类图的关系线大多是横向或纵向的。可以在选中连线后通过 Format 菜单里的线型设置调整也可以先把偏好改掉免得画完再一条条改。注意这些设置是保存在本地偏好里的换台机器要重新调。如果你是团队协作建议把一份配好的项目文件当模板发下去比口头描述设置项高效得多。3. 类图元素与六种关系逐个拆解3.1 类框的三段式结构与可见性符号一个标准的类框从上到下分三段这个结构很多人画错了还在用。最上面一段是类名中间一段是属性字段最下面一段是操作方法。三段之间用横线分隔如果某个类没有属性或方法对应的段可以留空但分隔线通常保留。属性列表里每一行的完整格式是可见性 名称: 类型 默认值。可见性用四个符号表示这四个符号必须记牢因为它们直接对应代码里的访问修饰符符号含义对应 Java 修饰符公有public-私有private#受保护protected~包内可见默认无修饰符操作那一行的格式是可见性 名称(参数名: 参数类型): 返回类型。比如 pay(amount: BigDecimal): Boolean。这里有个小白最容易犯的错把属性写成name: String却不写可见性。虽然语法上允许省略但在正式的设计图里省略可见性等于放弃了封装设计评审的时候一定会被问。我的习惯是每一个属性和方法都明确写可见性哪怕只是画个草图。另外提一句命名规范这不是 UML 强制要求但团队里统一了会舒服很多类名用大驼峰属性和方法用小驼峰接口名有的团队喜欢加I前缀不过现在主流趋势是不加。StarUML 不会自动帮你规范命名得靠自觉。3.2 抽象、静态、派生这几个标记怎么用除了可见性类图上还有几个隐形标记画错了语义就全变了。抽象类的名字用斜体表示抽象方法的名字也用斜体。这是个硬约定别为了美观手工给某个类设斜体那会被理解成抽象类。在 StarUML 里正确做法是选中类在属性面板里把Is Abstract勾上类名会自动变斜体语义和显示一致。静态成员用下划线表示静态属性加下划线静态方法也加下划线。在 StarUML 里对应Is Static属性。派生属性也就是可以由其他属性算出来的属性在名字前面加一个斜杠比如/totalAmount。这个标记用的人不多但在涉及金额、统计这类场景时特别有用能告诉读者这个值不用存是算出来的。还有接口通常用interface这个构造型标注放在类名上方或者用圆形图标表示。我倾向于用构造型文本的方式因为导出成图片之后圆形图标的辨识度反而低。枚举用enumeration标注枚举值列在属性段里。这些标记看起来很琐碎但它们构成了类图的精度。一张没有可见性、没有抽象标记的类图本质上和随手画的方框图没有区别也就失去了被称为类图的意义。3.3 六种关系的箭头画法与一句话判断法这部分是核心也是问得最多的。类图箭头怎么区分五种关系怎么画出区别——每年都有新人在这个问题上卡住。先给结论常见的类图关系一共六种很多教材说五种是因为把依赖单独拎出来讲或者把聚合和组合合成聚合一类。我建议六种全记住因为它们在代码里的表现形式完全不同。关系英文名线型端点符号代码中的典型表现泛化Generalization实线空心三角指向父类extends实现Realization虚线空心三角指向接口implements关联Association实线普通箭头或无箭头长期持有的成员变量聚合Aggregation实线空心菱形位于整体一侧成员变量可外部传入、可共享组合Composition实线实心菱形位于整体一侧成员变量由整体自己创建依赖Dependency虚线普通箭头指向被依赖方方法参数、局部变量、静态调用记忆的时候可以用三句口诀串起来。是不是用泛化能不能用实现。子类是一种父类用实线空心三角某个类能履行某个契约用虚线空心三角。三角永远指向被继承或被实现的那一端这一点画反了是最高频的错误。整体和部分同生共死用组合否则用聚合。生命周期绑定这件事是唯一可靠的判据。订单和订单项是组合——订单被删除订单项没有任何存在意义订单和收货地址是聚合——地址是独立实体可以被多个订单引用删掉订单地址还在。菱形永远画在整体那一侧空心代表弱聚合实心代表强组合。临时借用一下用依赖。依赖是最弱的关系它的特征是不持有引用只是使用。方法里传进来的参数、方法内部 new 出来的局部对象、直接调用的静态方法都属于依赖。很多人把本来该画成依赖的东西画成了关联结果图上一堆线看起来耦合极重实际上是误会。提示画关系的时候如果拿不准是关联还是聚合就退一步问自己——我在代码里是把它当成员变量存着还是每次用的时候传进来。存着就是关联起步传进来基本就是依赖。这个判断不需要哲学思辨看代码最快。3.4 多重性、角色名与导航性光有线还不够一条关联线要表达完整信息还得配三个东西多重性、角色名、导航性。多重性写在连线两端表示数量约束常用的几种写法是写法含义1恰好一个0..1零个或一个0..*零个或多个1..*一个或多个2..5这个范围内的个数在 StarUML 里设置多重性的方法是选中关联线在属性面板里展开端点的设置项找到 Multiplicity 填进去。填的时候要注意端点对应的是哪个类——选中线的不同端属性面板会切换到对应的那一段设置这个交互很多人第一次用会懵。角色名写在线的末端用来命名这一端在对方视角里是什么。最经典的例子是自关联一个Employee类可以通过 manager 和 subordinate 两个角色名指向自己表示一个员工有一个经理一个经理管多个员工。没有角色名自关联线就是一堆看不懂的圈。导航性用箭头表示有箭头说明可以顺着这条线访问到对方。StarUML 里关联线默认不显示箭头需要手动设置端点的可导航属性。我的经验是设计阶段宁可把导航性标清楚因为它直接决定代码里谁是主动方。一个类能顺着引用访问另一个类意味着前者依赖后者的接口改起来是要牵连的。3.5 接口、抽象类与枚举三种特殊类的建模套路接口、抽象类和枚举在类图上都有专门的画法混用会让人读不懂设计意图。接口描述的是能力契约常见于策略、回调、仓储层。画接口时的关键是接口内部只放方法签名不出现任何属性除非是常量。如果一个接口里出现了非静态属性说明设计跑偏了那应该是抽象类。StarUML 里新建接口是通过工具箱里的 Interface 工具或者右键包选 Add Interface。抽象类是部分实现 部分留白。它的属性和普通类一样写抽象方法用斜体。抽象类和接口在代码上可以互相替代但在类图上语义不同抽象类表达共享实现接口表达统一能力。什么时候用哪个一般遵循有共享状态和共享实现的时候用抽象类只是行为约定的时候用接口。枚举用来表达有限取值集合比如订单状态、支付渠道。它的画法是把枚举值列在属性段。有个细节值得注意如果某个属性的类型是枚举把它画成类框并用枚举标注比直接写 String 强得多因为看的人立刻知道取值范围是有限且明确的。4. 实操从零画一个订单模块的类图4.1 需求拆解与类清单梳理光讲语法没意义我们用一个真实的场景走一遍。需求大致是用户下单订单包含多个订单项每个订单项关联一个商品订单需要有收货地址订单支持支付和取消支付方式有多种未来可能扩展。先做类清单这一步是纯思考别打开软件User用户基础用户信息VipUser会员用户继承 User有折扣率Order订单订单主体OrderItem订单项订单里的商品条目组合关系Product商品商品信息Address收货地址独立实体可复用Payable接口可支付能力AbstractPayment抽象类支付方式的公共实现AlipayPayment / CreditCardPayment具体支付方式OrderStatus枚举订单状态OrderService服务类编排下单流程这十一个类型刚好能覆盖六种关系是个理想的练手案例。你会发现清单里没有库存优惠券这些东西不是它们不重要而是刻意做减法——第一版类图只画主干细节等主干稳定了再加。新手最容易犯的错就是一次性想画全画到一半就放弃了。4.2 建类、填属性与方法的完整操作打开 StarUML新建项目右键根节点建一个 Package 叫order在包上右键 Add Diagram Class Diagram 建图。然后开始建类。建类是三步工具箱里选 Class 工具在画布上点一下双击类名改成Order。重复这个动作把十一个类型建完。这一步有个提效技巧把类先全部摆出来再统一填内容不要在画布上画一个填一个那样思路会断断续续。填属性和方法有两条路。第一条是双击类框直接编辑文本光标在类名段、属性段、操作段之间用 Tab 或方向键切换。这种方式快但带参数的方法容易解析错比如pay(amount: BigDecimal): Boolean这种带类型的方法签名手工敲的话括号和冒号的位置一定要准。第二条是选中类在右侧属性面板的 Attributes 和 Operations 页签里一条条加每个字段都是结构化的名称、类型、可见性三段。我推荐第二条路慢一点但不会出错尤其是后面要生成代码的时候结构化数据才不会出岔子。以Order类为例属性段填这些 id: Long orderNo: String createdAt: Date - status: OrderStatus totalAmount: BigDecimal注意status我用了减号因为状态变更必须通过方法外部不能直接改。OrderItem类则要突出自己的职责 quantity: int unitPrice: BigDecimal subtotal(): BigDecimalsubtotal()这个方法返回单价乘数量其实也可以写成派生属性/subtotal: BigDecimal两种表达都对我习惯写成方法因为代码里也是一次计算。Payable接口里只放两个方法 pay(amount: BigDecimal): Boolean refund(amount: BigDecimal): BooleanOrderStatus枚举的值填在属性段用大写CREATED PAID SHIPPED FINISHED CANCELED这一步做完画布上应该有十一个框内容都填好了。看起来有点朴素但这就是专业类图的常态花哨不是目标准确才是。4.3 连关系逐条判断的思考过程记录接下来是最关键的环节连关系。我会把每一条的判断过程写出来你可以对照着感受一下为什么是这种关系。第一条Order 与 OrderItem。订单项离开订单没有意义订单删除时订单项一并消失生命周期绑定。所以是组合实心菱形画在 Order 一侧。多重性是 Order 端1OrderItem 端1..*一个订单至少一个订单项才成立。用工具箱里的 Composition 工具先点 Order 再点 OrderItem这样菱形才会落在 Order 上。这一步超级容易画反画反了最省事的做法是删掉重来比在属性面板里调整端点快。第二条OrderItem 与 Product。订单项引用商品商品本身是独立的、长期存在的实体。订单项不是拥有商品只是指向它。所以是关联从 OrderItem 指向 Product多重性是1对1。这里要不要加导航性箭头我的做法是加上因为代码里是 OrderItem 持有 Product 的引用方向明确。第三条Order 与 Address。地址可以被多个订单复用删掉订单地址依然存在。所以是聚合空心菱形在 Order 一侧多重性 Order 端1、Address 端1一个订单一个地址但一个地址可以服务多个订单。第四条VipUser 与 User、AlipayPayment/信用卡支付 与 AbstractPayment。这两组都是泛化实线空心三角指向父类。用 Generalization 工具先点子类再点父类画反了三角会指向子类语义完全错。第五条AbstractPayment 与 Payable。抽象类实现了接口用实现关系虚线空心三角指向 Payable。在 StarUML 工具箱里实现关系的工具和泛化挨着注意别点错两者只差线型。第六条OrderService 与 Order、Payable。服务类只是编排流程不持有这些对象的引用方法里作为参数使用。所以是依赖虚线普通箭头指向 Order另一条指向 Payable。第七条User 与 Order。用户可以拥有多个订单这是关联User 端1Order 端0..*。这里有个设计讨论点是 User 关联 Order还是 Order 关联 User如果业务上经常查某人的所有订单从 User 出发更方便如果只做单订单查询从 Order 指向 User 更自然。这种取舍没有标准答案取决于查询方向也值得写进图的注释里。第八条Order 与 OrderStatus。状态是枚举通常是关联或者直接把枚举作为属性类型。我一般用属性类型的方式表达不单独连线图更干净。如果非要连线用带约束的关联标注也可行。连完这八条六种关系就全出现了泛化、实现、关联、聚合、组合、依赖。你可以把这张图当成关系全家桶来比对看看每种线型和端点符号是不是和表格里对得上。4.4 排版、校验与导出的细节线连完了但图大概还是乱的。排版这件事我是这么做的。先做局部对齐。同类层的类摆在同一水平线上比如把所有实体类放一排所有服务类放另一排。选中多个元素后用 Format 菜单里的对齐和分布功能一次搞定一排。手工拖到眼睛看着齐的程度是很难的一定要用工具对齐。再做连线优化。选中连线把走线样式改成折线斜着拉的对角线立刻变规整。折线之间的交叉能减少很多读起来舒服一大截。接着调整多重性标签的位置。StarUML 会自动放置这些文本有时候会和类框重叠或者压在线上。直接拖动标签到空白处即可它会记住位置。最后做模型校验。Model 菜单下有个校验功能快捷键是 CtrlAltV它会扫出未命名的元素、重复命名之类的问题。我在交付前一定会跑一遍被揪出来的往往是复制粘贴留下的无名类这种低级问题出现在正式文档里挺掉价的。导出的时候优先选 SVG。SVG 是矢量格式插到文档里放大不糊这一点在打印或者投屏时会救命。如果必须用位图导出 PNG 时把分辨率调高别用默认值。另外有个很实用的操作选中一整张图导出和只导出选中的几个元素是不同层级的入口做文档插图的时候后者更常用。4.5 从代码反向生成类图以及从类图生成代码骨架前面讲的都是手工画。实际情况中更常见的是反过来——已经有一堆代码想看看它长什么样。从 Java 反向生成的流程是先在扩展管理器里装好 Java 扩展然后通过 Tools 菜单里的反向工程入口选择代码目录StarUML 会自动扫出包结构和所有类生成一套类图。生成的图一般会很乱因为它是把全部类和全部依赖都画出来了。我的处理方式是把它当素材新建一张图从模型树里把关心的类拖进来自己重新布局。模型是自动生成的图是手工组织的这个分工要搞清楚否则你会被自动生成的蜘蛛网劝退。从类图生成代码则是反向路径把类图设计好之后通过 Tools 菜单里的代码生成功能选择目标语言和输出目录StarUML 会按包结构生成目录和类文件属性和方法都会带上去。生成的结果通常只是骨架方法体是空的但省掉了建目录、写字段、写 getter 这些机械工作。我在做新模块的时候会先用这个方式把骨架搭出来然后往里面填业务逻辑。如果你用 IDEA也可以直接用内置的 Diagram 功能看现状。对着目标包或类按快捷键出图能快速看到类之间的依赖关系而且它读的是编译后的真实结构不会有图和代码不一致的问题。缺点是布局不可控类一多就没法看适合排查而不是交付。5. 常见问题与排查速查表画类图踩的坑八成集中在下面这些地方。我按现象、原因、怎么修整理成表遇到问题直接对号入座。现象常见原因处理方式泛化的三角指向子类画线时起点终点选反删掉重画先点子类再点父类聚合/组合的菱形画在了部分一侧起点终点选反删掉重画先点整体再点部分关联线上没有多重性端点属性未设置选中线在端点设置里填 Multiplicity类名自动变成斜体勾了 Is Abstract取消抽象属性或确认本来就该抽象属性方法编辑后代码生成报错文本解析歧义改用属性面板的结构化字段逐条填写移动类时线变乱未对齐、走线为斜线对齐功能排布走线切成折线导出的图放大后糊导出为位图且分辨率低改用 SVG 导出反向工程菜单找不到未安装对应语言扩展进扩展管理器按语言安装一个类改了名字老的图还在存在两个同名不同包的类在模型树里查重删除冗余元素复制类粘贴后关系全断复制方式导致引用丢失重新连关系或改用复制后重建引用的方式再补充几个表里放不下的细节。关于关系画不上的情况。有时候你想从 A 拉一条线到 B怎么点都没反应。常见原因是点在类的文字区域内而不是边框上不同工具对热区的处理不一样。我的做法是点在类的边缘空白处开始拖。如果还是不行就改用工具箱里的关系工具先点 A 再点 B这是最稳的方式。关于线太多看不清。一张图上的关联线超过二十条可读性就急剧下降了。解决办法不是换更大的显示器而是拆图。按业务模块拆或者按层次拆领域层一张、服务层一张。我在一个订单系统里拆过四张图评审的时候一张张讲比憋一张大图效率高得多。关于评审时被追问实现细节。类图不描述时序和流程有人问这个调用顺序是什么的时候说明该上时序图了。类图和时序图是配合使用的别指望一张图回答所有问题。这个边界我踩过坑曾经试图在类图里用注释把所有流程都写清楚结果图变成了代码的另一种写法谁也不想看。关于协作与版本管理。StarUML 的项目文件是文本格式的可以进版本库但多人同时改同一个文件冲突会很难解。我的做法是一个模块一个文件各自负责各自的避免多人编辑同一个项目文件。6. 用久了才明白的几条经验画类图这些年真正让我少走弯路的不是 UML 语法而是几个观念上的调整随手记在这里。第一条是类图不是文档是思考工具。我见过太多团队为了交付一份 UML 文档而画图画完就归档代码里一行都没对应上。真正有用的类图是在动手写代码之前画的用来暴露设计问题。画的过程中如果发现某个类被所有其他类引用或者继承层次深到五层问题在设计阶段就已经被发现了这比写完两万行代码再回头重构便宜太多。第二条是图要和代码保持一致但不用追求完全一致。完全一致意味着把所有 getter、setter、日志字段都画上去图就没人看了。我的尺度是核心业务字段画框架性的东西不画核心关系画工具类之间的依赖不画。这个不画什么的判断力比画什么更能体现设计水平。第三条是枚举和值对象值得单独画。很多人的类图里全是实体类看不到枚举和值对象结果评审时大家对着一个status: String猜取值范围。把枚举画出来成本很低收益很高。最后分享一个我常用的自检动作画完之后随机挑一条关系线问自己如果这个关系变了代码里要改几个地方。如果答案是要改十几个文件说明这条关系耦合过重可能是把依赖画成了关联或者抽象层次不对。类图的价值就在于此它把耦合关系摆在明面上让你没法装作看不见。如果要继续深入下一步可以练的是把这张类图和时序图对上——挑一个下单流程把参与的对象和消息顺序画出来。两张图能对得上说明你的模型基本站得住对不上八成是某个职责放错了类。