——从 Java 到 Flutter 的统一架构认知

在做 Java 后端、Flutter、甚至前端工程时,你一定见过这些名词:

  • DTO

  • DAO

  • VO

  • Entity

  • Repository

但很多人是:

“听过、用过、但说不清楚区别”

这篇文章,我从 工程实践 + 架构设计 的角度,帮你一次性理清这些概念,并给出一套真正能落地的结构模型

一、先给结论

只记住这 5 句话就够了:

DTO 是数据长什么样
DAO 是数据从哪来
Repository 是业务入口
Entity 是业务实体
VO 是业务中的“值”

二、整体架构图(核心)

下面这张图,是整篇文章的核心 👇
你可以把它当成「后端 / Flutter / Clean Architecture 通用模型」。

✅ 架构图(通用版)

┌──────────────┐
│    UI / 页面  │
└───────┬──────┘
        │
        v
┌─────────────────────────────┐
│ ViewModel / Controller / Bloc│
└───────────┬─────────────────┘
            │
            v
┌─────────────────────────────┐
│ Repository(业务入口 / 门面) │
└───────┬───────────┬─────────┘
        │           │
        │           │
        v           v
┌──────────────┐  ┌──────────────┐
│ DAO(Remote)  │  │ DAO(Local)   │
│ 接口 / HTTP   │  │ DB / 缓存     │
└───────┬──────┘  └───────┬──────┘
        │                 │
        v                 v
   ┌─────────┐       ┌─────────┐
   │  DTO     │       │  DTO     │
   │ JSON模型  │       │ 本地模型  │
   └────┬────┘       └────┬────┘
        │                 │
        └──────┬──────────┘
               v
        ┌──────────────┐
        │   Mapper      │
        │ DTO → Domain  │
        └──────┬───────┘
               v
     ┌─────────────────────┐
     │ Domain(业务模型层) │
     ├───────────┬─────────┤
     │ Entity     │ VO      │
     │ 有ID        │ 无ID     │
     └───────────┴─────────┘

三、DTO:数据传输对象(Data Transfer Object)

✅ 定义

DTO 是 专门用于数据传输的对象,通常直接对应接口返回结构。

特点

  • 只负责装数据

  • 字段名跟接口一致

  • 可以为 null

  • 不包含业务逻辑

  • 生命周期短

Java 示例

public class UserDTO {
    private String userName;
    private String avatar;
}

Flutter 示例

@freezed
class UserDto with _$UserDto {
  const factory UserDto({
    String? userName,
    String? avatar,
  }) = _UserDto;

  factory UserDto.fromJson(Map<String, dynamic> json)
      => _$UserDtoFromJson(json);
}

DTO 就是一个数据容器,用来接收或传递数据,本身不承载业务含义。

四、DAO:数据访问对象(Data Access Object)

✅ 定义

DAO 负责 从哪拿数据

可能是:

  • HTTP 接口

  • 数据库

  • 本地缓存

  • 文件系统

Java 示例

public interface UserDao {
    UserDTO getUser();
}

Flutter 示例

class UserRemoteDataSource {
  Future<UserDto> getUser() async {
    final res = await dio.get('/user');
    return UserDto.fromJson(res.data);
  }
}

DAO 的特点:

  • 不关心业务
  • 不做转换
  • 只负责“拿数据”

五、Repository:整个架构的核心

✅ 定义

Repository 是 业务访问的统一入口

它负责:

  • 决定用远程还是本地数据
  • 调用 DAO
  • DTO → Domain 转换
  • 向上层隐藏数据来源

示例

class UserRepository {
  final UserRemoteDataSource remote;

  Future<User> getUser() async {
    final dto = await remote.getUser();
    return dto.toDomain();
  }
}

 Repository 是:

架构中最重要的一层,没有之一

六、Entity:业务实体(有身份)

定义

Entity 是 有身份、有生命周期的业务对象

class User {
  final String id;
  final String name;
}

特点:

  • 有 ID
  • 可以变化
  • 代表“某一个具体对象”

七、VO:值对象(最容易被误解)

正确含义(DDD)

VO(Value Object)是没有 ID、只看值是否相等的对象

特点

  • 不可变
  • 无 ID
  • 有业务语义
  • 可复用

示例

@freezed
class Email with _$Email {
  const factory Email(String value) = _Email;

  factory Email.parse(String input) {
    if (!input.contains('@')) {
      throw Exception('Invalid email');
    }
    return Email(input);
  }
}

 VO 是“业务里的名词”,不是数据结构。

八、为什么 Java 项目里也有 VO 文件夹?

因为很多 Java 项目里的 VO,其实是:

👉 View Object(返回给前端的对象)

public class UserVO {
    private String name;
    private String avatar;
    private String vipText;
}

这种 VO 的本质是:

✅ 返回模型
❌ 不是 DDD 的 Value Object

九、两种 VO 的最终区分

类型含义是否业务模型
VO(Java 常见)View Object
VO(DDD)Value Object

十、最终总结(背)

DTO:数据怎么传
DAO:数据从哪来
Repository:业务入口
Entity:业务对象
VO:业务中的值

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐