DTO和VO
-
VO:展示层需要展示的数据。
-
DTO:业务逻辑层需要接收的数据和返回的数据。
VO与DTO的属性值基本相同,但是VO是DTO的最终解释,可以对DTO的字段进行适当删减。作为前端开发者,我们可以理解为DTO就是后端返回给我们的数据结构,VO是view上需要显示的数据结构。
很多人在项目中没有很好的分层,一般会写出这样的代码:
const DataList = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://xxxx/data')
.then(res => res.json())
.then(data => setData(data)); }, []);
return ( <ul>
{data.map(item => ( <Item {...item} key={item.id} /> ))}
</ul> ); }
但是在实际的项目维护中,后端的接口是很容易变动的,不仅返回的数据结构可能改变,甚至接口地址、接口版本都会改变,如果不能清晰的划分前端的分层,那么应对这种变动就需要侵入前端代码作出巨大的改动。下面我们来学习一下如何进行前端分层。
分层结构
我们从下往上逐层来分析:
- API层,这一层作为整个分层的最底层,是整个项目根本的的数据来源,通过使用封装过的request实例依照接口文档进行最基本的接口对接。在这一层,你应该对request实例进行简单的配置,如token、baseUrl、错误重试、缓存请求结果、合并重复请求等等。
//这是最简单的api层结构
interface User {
id: number;
name: string;
email: string;
}
const getUser = async (): Promise<User> => {
const data = await (await fetch("https://api.xxx.com/api/v1/user")).json()
return data as User
}
interface Post {
id: number;
userId: number;
title: string;
body: string;
}
const getPosts = async (userId: number): Promise<Post[]> => {
const data = await (
await fetch(`https://api.xxx.com/api/v1/post?userId=${userId}`)
).json()
return data as Post[]
}
-
Model层,这里是体现view层数据结构VO的层级,通过防腐层的包裹将api层中DTO结构适配成展示视图所需要的VO结构。
防腐层: HAL 的设计思想在领域驱动设计(DDD) 中又被称为防腐层(Anticorruption Layer)。在 DDD 定义的多种上下文映射关系中,防腐层是最具有防御性的一种。它经常被使用在下游团队需要阻止外部技术偏好或者领域模型入侵的情况,可以帮助很好地隔离上游模型与下游模型。
行业内有很多种方式可以实现防腐层,如
GraphQL
、BFF
或者前端数据层隔离,在一般业务开发环境下,前后端的关系通常为客户/供应商或者跟随者/被跟随者的关系。其中GraphQL
对后端侵入度最高,寄希望于后端配合前端对接口进行 GraphQL 改造不太现实;BFF 的构建需要额外的机器资源及运维成本。所以在前端数据层搭建防腐层几乎成了绝大多数项目的最优解。我们可以简单使用rxjs来搭建防腐层,将DTO转换成VO
之后后端返回有数据结构的变动,我们只需要在防腐层管道里进行变更就好,无需侵入view层代码,而且就算多版本接口并存,或者某个VO数据需要通过多个请求的DTO得出也可以通过防腐层轻易保证稳定性。
- view层,在整个项目的视图层中,我们可以毫无顾忌的使用model层中的数据,而不必担心后续的非业务功能改动。但需要注意,为了代码结构更加规范,view层中从model层获取数据一定要依赖hook,只有hook和hander可以影响视图,但请不要在你的jsx/tsx文件中出现
useEffect
,你可以使用这样简单的封装,或者使用swr
或者tanstack query
这样的请求库
还应注意,view层中,应该只有hander可以响应视图的交互,hander是形如handleXXX
的函数,这是一种命名规范,也是清晰结构的要求,通过一层handleXXX
函数的包装,你点击按钮发送的api层的post请求和页面主题切换等交互才可以加入loading、error等状态影响视图中的显示状态。
前端分层通过API层对接数据源,Model层防腐转换DTO为VO,View层Hook管理数据流。DTO承载接口原始结构,VO适配视图需求,防腐层隔离后端变动,提升代码维护性和稳定性,实现业务与视图解耦。
现在工程化的前端体系下,良好的分层结构可以帮助我们代码更好的维护,更加的稳定,希望大家阅读本文能有所收获!笔者目前还是大二的小白,见识短浅,若有错误还请评论区指出