You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在UML类图中展示Data Transfer Object(DTO)?附示例

UML类图中DTO的正确展示方法

DTO的核心定位是跨边界(跨层、跨服务、跨进程)传输的纯数据载体,没有业务逻辑,建模时只要把这个核心特征体现清楚,就不会出大问题。

核心建模规则

  • 必须给DTO类加<<DTO>>构造型标记,放在类名上方的构造型位置,和领域实体、值对象、配置类等其他类做明确区分,这是最直观的识别标识
  • 类成员只保留数据相关内容:可以定义私有字段、无参/全参构造方法、属性get/set方法,绝对不能出现业务计算、流程判断、数据校验这类业务逻辑方法;如果是框架强制要求实现的序列化接口(比如Java的Serializable),可以保留实现关系,其他无关接口一律不要加
  • 关联关系统一用**依赖(虚线箭头)**和上下游类连接:DTO是请求/响应维度的瞬时对象,没有长期被持有的生命周期,不要画组合、聚合、双向关联这类强绑定关系
  • 嵌套DTO直接按实际包含关系关联,标注清楚多重性即可,比如分页包装DTO和内部列表项DTO是1对多的关系,直接标1对0..*就行;带泛型的包装DTO可以直接用UML泛型标记类名~泛型参数~展示

实际建模示例

下面是用户管理业务场景下的DTO建模参考,覆盖了请求DTO、响应DTO、继承、泛型包装、嵌套、跨层调用的完整关系:

classDiagram
    class Serializable {
        <<interface>>
    }
    class PageQueryDTO {
        <<DTO>>
        - Integer pageNum
        - Integer pageSize
        + PageQueryDTO()
        + getPageNum() Integer
        + setPageNum(Integer pageNum) void
        + getPageSize() Integer
        + setPageSize(Integer pageSize) void
    }
    class UserQueryDTO {
        <<DTO>>
        - String keyword
        - Integer status
        + UserQueryDTO()
        + getKeyword() String
        + setKeyword(String keyword) void
        + getStatus() Integer
        + setStatus(Integer status) void
    }
    class UserInfoDTO {
        <<DTO>>
        - Long userId
        - String username
        - String email
        - LocalDateTime createTime
        + UserInfoDTO()
        + getUserId() Long
        + setUserId(Long userId) void
        + getUsername() String
        + setUsername(String username) void
        + getEmail() String
        + setEmail(String email) void
        + getCreateTime() LocalDateTime
        + setCreateTime(LocalDateTime createTime) void
    }
    class PageResultDTO~T~ {
        <<DTO>>
        - Long total
        - Integer pageNum
        - Integer pageSize
        - List~T~ records
        + PageResultDTO()
        + getTotal() Long
        + setTotal(Long total) void
        + getPageNum() Integer
        + setPageNum(Integer pageNum) void
        + getPageSize() Integer
        + setPageSize(Integer pageSize) void
        + getRecords() List~T~
        + setRecords(List~T~ records) void
    }
    class UserController {
        <<controller>>
        + queryUserList(UserQueryDTO query) PageResultDTO~UserInfoDTO~
    }
    class UserService {
        <<service>>
        + listUser(PageQueryDTO page, UserQueryDTO query) PageResultDTO~UserInfoDTO~
    }
    class OpenApiClient {
        <<client>>
        + fetchUserList(UserQueryDTO query) PageResultDTO~UserInfoDTO~
    }

    PageQueryDTO <|-- UserQueryDTO
    PageResultDTO *-- "0..*" UserInfoDTO
    Serializable <|.. PageQueryDTO
    Serializable <|.. UserQueryDTO
    Serializable <|.. UserInfoDTO
    Serializable <|.. PageResultDTO
    UserController ..> UserQueryDTO
    UserController ..> PageResultDTO
    UserController ..> UserService
    UserService ..> PageQueryDTO
    UserService ..> UserQueryDTO
    UserService ..> PageResultDTO
    OpenApiClient ..> UserQueryDTO
    OpenApiClient ..> PageResultDTO

这个示例完全对齐实际开发规范:所有DTO都有明确构造型标记,没有多余业务方法,和上下游的控制层、服务层、外部客户端关系统一用依赖表示,泛型、继承、嵌套关系都做了明确标注,可以直接套用到业务建模里。

常见建模误区

  • 不要给DTO加业务方法:比如不要在UserInfoDTO里写邮箱格式校验、权限判断这类逻辑,这类逻辑要放到业务层或者专门的校验组件里,DTO只负责存数据
  • 不要把DTO和领域实体画成等价类:二者可能字段高度重合,但职责完全不同——领域实体带业务行为,DTO只做传输,必须分开建模
  • 不要给DTO加强生命周期关联:DTO随着请求/响应结束就会被销毁,不存在被某个服务长期持有、和服务同生命周期的情况,别画组合、聚合这类强关联

内容的提问来源于stack exchange,提问作者abus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 15:06:25