Mermaid vs PlantUML 类图对比:语法差异、示例与选型

OnUML Team··7 min read
mermaidplantumlclass-diagramdiagram-as-codeuml

本文只关注类图本身的图形表达能力。 至于 Markdown 支持、文档平台集成、生态插件、渲染服务这些整体工具差异,本文不会展开,相关内容可以看系列总览:Mermaid vs PlantUML:2026 年该选哪个图表即代码工具?

在这个前提下,结论也很直接:日常用于说明领域模型、服务对象、接口关系和简单继承结构的类图,Mermaid 已经足够;如果你要做更接近正式 UML 的设计归档,尤其是包、命名空间、隐藏细节、关联类、复杂注释和统一样式,PlantUML 更稳。

它们都能表达类名、属性、方法、可见性、继承、组合、聚合、依赖、实现、基数和注解。真正影响选择的,通常不是“谁能不能画继承关系”,而是这张图是否需要更完整的 UML 元素、更强的模型裁剪能力、更复杂的包结构,或者更适合放进架构评审材料。

更准确的判断是:

Mermaid 胜在轻量直接。 对产品文档、README、技术方案和中小型领域模型来说,它的 classDiagram 语法短、可读、容易嵌入 Markdown。只要类数量不多、分组不复杂、样式要求不重,Mermaid 通常不会成为表达瓶颈。

PlantUML 胜在 UML 语义更完整。 它支持更多声明元素,例如 interfaceenumabstract classrecorddataclassprotocolexception 等,也有更成熟的包、命名空间、隐藏/移除成员、关联类、链接注释、布局辅助和 skinparam 样式能力,更适合复杂设计图和长期维护的架构图。

本文基于官方文档整理,并配合具体案例对比代码和图形效果:

Mermaid vs PlantUML 类图核心差异

对比点MermaidPlantUML选择建议
类、属性、方法支持支持两者都可以
可见性支持 +-#~支持 +-#~两者都可以
静态/抽象成员支持 $* 标记支持 {static}{abstract} 等更显式写法正式 UML 图 PlantUML 更清楚
继承/实现/组合/聚合/依赖支持常见关系支持常见关系两者都可以
基数支持关系两端标注支持关系两端标注两者都可以
泛型支持 ~T~,但复杂泛型有限制支持泛型表达复杂类型模型 PlantUML 更合适
接口/枚举/抽象类通过 annotation 表达interfaceenumabstract class 等声明元素PlantUML 语义更显式
包和命名空间支持 namespace支持 package、namespace 和多种包样式大型模型 PlantUML 更合适
隐藏成员和裁剪视图主要依赖配置和少量语法支持 hide、remove、restore、按标签裁剪设计评审 PlantUML 更合适
注释支持 notenote for支持方向注释、浮动注释、链接注释、字段/方法注释PlantUML 注释能力更细
关联类不突出支持 association class需要严格 UML 语义时选 PlantUML
样式控制支持 classDef、CSS class、主题配置支持 skinparam、颜色、stereotype 样式等统一图形规范 PlantUML 更合适

先给一句话结论:

Mermaid 类图适合把结构讲清楚;PlantUML 类图适合把结构、语义、裁剪视图和输出规范一起控制住。

Mermaid 也可以画清楚常见类模型

很多人以为类图只要进入继承、接口、组合、基数,就必须使用 PlantUML。这个判断并不准确。Mermaid 官方类图支持类成员、可见性、返回类型、泛型、常见 UML 关系、基数、annotation、note 和 direction,足以覆盖大多数文档型类图。

下面是一个订单领域模型:Order 拥有多个 OrderItem,使用 PaymentMethod 接口完成支付,并和 Customer 建立关联。

Mermaid 代码和图

classDiagram
  direction LR

  class Customer {
    +String id
    +String email
    +placeOrder()
  }

  class Order {
    +String id
    +OrderStatus status
    +Money total
    +addItem(productId, quantity)
    +checkout() PaymentResult
  }

  class OrderItem {
    +String productId
    +int quantity
    +Money price
    +subtotal() Money
  }

  class PaymentMethod {
    <<Interface>>
    +authorize(amount) PaymentResult
  }

  class CreditCardPayment {
    +String token
    +authorize(amount) PaymentResult
  }

  class OrderStatus {
    <<Enumeration>>
    CREATED
    PAID
    CANCELLED
  }

  Customer "1" --> "0..*" Order : places
  Order "1" *-- "1..*" OrderItem : contains
  Order --> PaymentMethod : uses
  PaymentMethod <|.. CreditCardPayment
  Order --> OrderStatus

PlantUML 代码和图

@startuml
left to right direction

class Customer {
  +id: String
  +email: String
  +placeOrder()
}

class Order {
  +id: String
  +status: OrderStatus
  +total: Money
  +addItem(productId, quantity)
  +checkout(): PaymentResult
}

class OrderItem {
  +productId: String
  +quantity: int
  +price: Money
  +subtotal(): Money
}

interface PaymentMethod {
  +authorize(amount): PaymentResult
}

class CreditCardPayment {
  +token: String
  +authorize(amount): PaymentResult
}

enum OrderStatus {
  CREATED
  PAID
  CANCELLED
}

Customer "1" --> "0..*" Order : places
Order "1" *-- "1..*" OrderItem : contains
Order --> PaymentMethod : uses
PaymentMethod <|.. CreditCardPayment
Order --> OrderStatus
@enduml

对这种中小型领域模型,Mermaid 已经可以把结构讲清楚。它不是只能画“几个方框加几条线”;类成员、接口标记、枚举标记、组合关系和基数都能表达。

PlantUML 的声明元素更接近正式 UML

两者都能表达接口和枚举,但语义颗粒度不同。Mermaid 通常用 <<Interface>><<Enumeration>> 这类 annotation 标记类的性质;PlantUML 可以直接声明 interfaceenumabstract class 等元素。

Mermaid 代码和图

classDiagram
  class Repository {
    <<Interface>>
    +findById(id) Entity
    +save(entity)
  }

  class SqlRepository {
    +findById(id) Entity
    +save(entity)
  }

  class BaseEntity {
    <<Abstract>>
    +String id
    +createdAt Date
  }

  BaseEntity <|-- User
  Repository <|.. SqlRepository

PlantUML 代码和图

@startuml
interface Repository {
  +findById(id): Entity
  +save(entity)
}

class SqlRepository {
  +findById(id): Entity
  +save(entity)
}

abstract class BaseEntity {
  +id: String
  +createdAt: Date
}

class User

BaseEntity <|-- User
Repository <|.. SqlRepository
@enduml

Mermaid 的 annotation 很适合文档说明;PlantUML 的声明元素更适合正式建模,因为读者能从语法和图形上同时看出元素类型。

PlantUML 更适合大型类图的裁剪和分组

类图一旦变大,真正困难的不是“能不能画出来”,而是“能不能只展示当前读者需要看的部分”。例如同一套领域模型,在产品说明里可能只展示公开方法,在代码设计评审里可能要展示字段、抽象类、包结构和内部依赖。

PlantUML 在这类场景更自然:它可以使用 package/namespace 分组,使用 hideshowremove 等命令裁剪成员或元素,还可以用 skinparam 控制输出风格。

PlantUML 代码和图

@startuml
skinparam classAttributeIconSize 0
hide empty members

package "order.domain" {
  abstract class AggregateRoot {
    +id: String
    #raise(event)
  }

  class Order {
    -items: List<OrderItem>
    +checkout()
    +cancel()
  }

  class OrderItem {
    -productId: String
    -quantity: int
  }
}

package "payment.domain" {
  interface PaymentGateway {
    +authorize(orderId, amount): PaymentResult
  }

  class StripeGateway {
    +authorize(orderId, amount): PaymentResult
  }
}

AggregateRoot <|-- Order
Order *-- OrderItem
Order ..> PaymentGateway
PaymentGateway <|.. StripeGateway

note right of Order
  Public methods are kept visible
  for the architecture review.
end note
@enduml

Mermaid 近似表达

classDiagram
  namespace order.domain {
    class AggregateRoot {
      <<Abstract>>
      +String id
      #raise(event)
    }

    class Order {
      -List~OrderItem~ items
      +checkout()
      +cancel()
    }

    class OrderItem {
      -String productId
      -int quantity
    }
  }

  namespace payment.domain {
    class PaymentGateway {
      <<Interface>>
      +authorize(orderId, amount) PaymentResult
    }

    class StripeGateway {
      +authorize(orderId, amount) PaymentResult
    }
  }

  AggregateRoot <|-- Order
  Order *-- OrderItem
  Order ..> PaymentGateway
  PaymentGateway <|.. StripeGateway

  note for Order "Public methods are kept visible\nfor the architecture review."

为什么这个场景更适合 PlantUML?

Mermaid 可以近似表达这张图,但能力边界不同:

  • Mermaid 的 namespace 可以做基础分组,PlantUML 的 package/namespace 和包样式更适合大型模型。
  • Mermaid 可以通过 hideEmptyMembersBox 等配置优化空成员框,PlantUML 可以更细地隐藏属性、方法、类、未连接类或带特定标签的元素。
  • Mermaid 的 note for 足够表达说明文字,PlantUML 的方向注释、浮动注释、链接注释、字段/方法注释更适合复杂评审图。
  • Mermaid 的 classDef 适合局部样式,PlantUML 的 skinparam 和 stereotype 样式更适合统一输出规范。

这就是 PlantUML 在类图里的真正优势:不是能不能画类和关系,而是能不能管理一个持续变大的模型视图。

Mermaid 更适合嵌入式说明图

如果你的类图主要放在 README、产品技术说明、轻量 ADR 或在线文档里,Mermaid 的优势很明显:代码短,阅读成本低,和 Markdown 内容贴得近。

Mermaid 代码和图

classDiagram
  class DiagramProject {
    +String id
    +String title
    +DiagramType type
    +save()
  }

  class Renderer {
    <<Interface>>
    +render(source) SvgResult
  }

  class MermaidRenderer {
    +render(source) SvgResult
  }

  class PlantUmlRenderer {
    +render(source) SvgResult
  }

  DiagramProject --> Renderer : uses
  Renderer <|.. MermaidRenderer
  Renderer <|.. PlantUmlRenderer

  note for Renderer "A renderer converts diagram source into SVG."

这类图的目标不是完整建模,而是让读者快速理解代码结构。对这种“解释一个模块”的场景,Mermaid 的轻量感反而是优点。

类图选择建议

选 Mermaid 写类图,如果这张图的重点是:

  • 展示一个中小型领域模型。
  • 说明几个类之间的继承、实现、组合和依赖关系。
  • 放在 README、Markdown 文档、产品技术说明或轻量设计文档里。
  • 读者需要快速看懂结构,而不是审查完整 UML 语义。
  • 图的规模可控,不需要频繁生成多个裁剪视图。

选 PlantUML 写类图,如果这张图的重点是:

  • 表达更正式的 UML 类图语义。
  • 需要直接声明 interfaceenumabstract classrecorddataclass 等元素。
  • 需要 package、namespace、多种包样式或大型模型分组。
  • 需要隐藏属性、隐藏方法、移除元素、展示不同评审视图。
  • 需要关联类、字段/方法注释、链接注释或更复杂的说明结构。
  • 需要稳定的样式规范,例如统一字体、颜色、stereotype 和输出风格。

常见问题

Mermaid 类图支持继承、组合和聚合吗?

支持。Mermaid 官方类图支持继承、组合、聚合、关联、依赖、实现、实线链接和虚线链接等常见关系,也支持关系两端的基数标注。不要因为图里有继承或组合,就直接判断 Mermaid 不够用。

Mermaid 类图支持接口和枚举吗?

支持表达,但方式更偏 annotation。你可以使用 <<Interface>><<Enumeration>> 这类标记说明类的性质。PlantUML 则可以直接使用 interfaceenum 等声明元素,语义更显式。

PlantUML 类图一定比 Mermaid 更适合所有项目吗?

不一定。如果你的图只是为了说明几个类的关系,PlantUML 的完整能力可能用不上。Mermaid 更轻、更适合嵌入 Markdown,也更适合快速维护。PlantUML 更适合大型模型、正式 UML、架构评审和需要长期统一输出风格的场景。

只看图形能力,Mermaid 和 PlantUML 类图怎么选?

如果图的重点是“让读者快速理解结构”,Mermaid 通常就够了。如果图的重点是“准确表达 UML 语义并维护多个复杂视图”,PlantUML 更合适。

最终结论:

在类图这一项上,Mermaid 的基础表达能力已经很完整;PlantUML 的优势主要体现在更丰富的 UML 元素、更强的视图裁剪、更成熟的分组和样式控制。轻量说明选 Mermaid,正式建模和复杂架构图选 PlantUML。

你可以在 OnUML 编辑器 中分别使用 Mermaid 和 PlantUML 模式,把上面的示例复制进去对比效果。