各层命名规约
各层命名规约
A)Service / DAO 层方法命名规约:
1)获取单个对象的方法用 get 做前缀。
2)获取多个对象的方法用 list 做前缀,复数结尾,如:listObjects
3)获取统计值的方法用 count 做前缀。
4)插入的方法用 save / insert 做前缀。
5)删除的方法用 remove / delete 做前缀。
6)修改的方法用 update 做前缀。
B)领域模型命名规约:
1)数据对象:xxxDO,xxx 即为数据表名。
2)数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
3)展示对象:xxxVO,xxx 一般为网页名称。
4)POJO 是 DO / DTO / BO / VO 的统称,禁止命名成 xxxPOJO。
分层领域模型规约:
-
POJO(Plain Ordinary Java Object): POJO 专指只有 setter / getter / toString 的简单类,在日常的代码分层中pojo会被分为VO、BO、 PO、 DTO。通过各层POJO的使用,有助于提高代码的可读性和可维护性。
-
DO(Data Object):专指数据库表一 一对应的 POJO 类。此对象与数据库表结构一 一对应,通过 DAO 层向上传输数据源对象。
- 一个是阿里巴巴的开发手册中的定义:DO( Data Object)这个等同于上面的PO
- 另一个是在DDD(Domain-Driven Design)领域驱动设计中:DO(Domain Object)这个等同于上面的BO
-
PO(Persistent Object):也指数据库表一 一对应的 POJO 类。此对象与数据库表结构一 一对应,通过 DAO 层向上传输数据源对象。
-
DTO(Data Transfer Object ):数据传输对象,Service 或 Manager 向外传输的对象。
-
BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象。
-
Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类来传输。
-
VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
DTO 通常使用在业务层与数据访问层之间进行传输,VO 则用于前后端数据传输。
在实际应用中,DTO 和 VO 更多的是一种标准化开发手段,它们通常不会带来额外的功能性价值增量,而只是提供一种规范化的数据传输和展示格式,以减少数据转换的麻烦。
VO(Value Object)值对象
VO(Value Object)是一种用于封装值或属性的对象,通常用于表示系统中的某种领域概念或者包装多个属性,以便更方便地传递和处理。
- 前端展示的数据,在接口数据返回给前端的时候需要转成VO
- 使用场景,在接口层服务中,将DTO转成VO,返回给前台
// VO:ProductVO(值对象),用于展示商品信息给前端页面。
public class ProductVO {
private String name;
private BigDecimal price;
private String description;
// 构造方法
public ProductVO(String name, BigDecimal price, String description) {
this.name = name;
this.price = price;
this.description = description;
}
// getter和setter方法
}
ProductVO是一个值对象,用于封装商品的相关属性,包括名称、价格和描述。它主要用于展示层或前端页面需要的数据。
使用VO的优势是将多个属性打包为一个对象,方便在展示层或前端页面进行数据展示和交互。例如,在控制器层获取到业务逻辑返回的商品信息后,可以将相关属性赋值给ProductVO对象,然后将ProductVO对象传递给视图层进行展示。
@Controller
public class ProductController {
private ProductService productService;
@GetMapping("/products/{id}")
public ModelAndView getProductDetails(@PathVariable("id") Long id) {
ProductDTO productDTO = productService.getProductById(id);
if (productDTO != null) {
// 创建ProductVO对象并设置属性
ProductVO productVO = new ProductVO(productDTO.getName(), productDTO.getPrice(), productDTO.getDescription());
// 将ProductVO对象传递给视图层展示
return new ModelAndView("product-details", "product", productVO);
}
return new ModelAndView("error");
}
}
DTO(Data Transfer Object)数据传输对象
DTO主要用于在不同层之间传递数据,它通常是一个简单的Java Bean,包含了要在系统各个层之间传输的数据。DTO不包含业务逻辑,它的目标是将数据从一个层传递到另一个层,以避免直接暴露底层实体对象。
- 在服务器的调用中,传输的数据对象
- DTO是可以存在于各层服务中(接口、服务、数据库等等)服务间的交互使用DTO来解耦
public class UserDTO {
private String username;
private String email;
private int age;
// 构造方法
public UserDTO(String username, String email, int age) {
this.username = username;
this.email = email;
this.age = age;
}
// getter和setter方法
}
UserDTO是一个简单的数据传输对象,包含了用户名、邮箱和年龄属性,以及相应的getter和setter方法。它没有业务逻辑和复杂的操作,纯粹用于在不同层之间传输用户数据。
使用DTO的优势是可以将多个属性打包到一个对象中,方便在不同层之间传递数据。例如,在服务层获取到数据库中的用户信息后,可以创建一个UserDTO对象,将相关属性赋值给DTO对象,然后将DTO对象传递给控制层或前端页面,以供展示和操作。
public class UserService {
private UserRepository userRepository;
public UserDTO getUserById(Long id) {
User user = userRepository.findById(id);
if (user != null) {
// 创建UserDTO对象并设置属性
UserDTO userDTO = new UserDTO(user.getUsername(), user.getEmail(), user.getAge());
return userDTO;
}
return null;
}
}
在上述代码中,UserService中的getUserById方法从数据库中获取到用户信息,并创建一个UserDTO对象,将相关属性赋值给DTO对象。然后,可以将UserDTO对象返回给调用方,避免直接暴露数据库实体对象。
通过使用DTO,可以简化数据传输和降低耦合性,不同层之间只需要依赖DTO对象的定义,而不需要了解底层实体对象的结构和细节。这样可以提高代码可维护性和灵活性,并减少不必要的网络通信量。
BO(Business Object)业务对象
DTO用于数据传输和跨层间的数据封装,目标是简化数据传输和提高性能;而BO用于封装和处理复杂的业务逻辑,负责实现具体的业务规则和操作。
BO(Business Object)是用于封装和处理复杂的业务逻辑的对象。它负责协调多个领域对象之间的交互,并提供具体的业务操作和规则。
- 主要在服务内部使用的业务对象
在一些软件开发中,BO(Business Object)可以被视为业务逻辑层的一部分。因此,可以说BO是与业务相关的组件或类,用于封装和处理复杂的业务逻辑。
- BO可以包含一系列的方法和操作,用于执行具体的业务功能。这些功能可能涉及多个数据操作、服务调用和其他业务规则的处理。BO通常与数据库交互并协调不同的数据操作,以满足特定的业务需求。
- 而"service" 是一种更通用的术语,它可以代表任何提供服务的组件或类。在实际开发中,"service" 通常指的是业务逻辑层的组件或类,负责协调各个领域对象之间的交互,并提供业务相关的功能接口供其他模块调用。
因此,在某些情况下,BO 可以与 Service 实现类相对应,它们都承载了业务逻辑的责任。但需要注意的是,BO和Service不完全等同。BO更强调业务逻辑的封装和处理,而Service更侧重于提供服务的组织和管理。
public class ProductBO {
public class OrderBO {
private OrderRepository orderRepository;
private ProductRepository productRepository;
public OrderBO(OrderRepository orderRepository, ProductRepository productRepository) {
this.orderRepository = orderRepository;
this.productRepository = productRepository;
}
public void createOrder(User user, List<Long> productIds) {
// 根据用户信息和商品ID查询相应的实体对象
UserEntity userEntity = userRepository.findById(user.getId());
List<ProductEntity> products = productRepository.findProductsByIds(productIds);
// 验证用户和商品信息等业务逻辑处理
if (userEntity == null || products.isEmpty()) {
throw new BusinessException("Invalid user or products");
}
// 创建订单并关联用户和商品
OrderEntity order = new OrderEntity();
order.setUser(userEntity);
order.setProducts(products);
// 保存订单到数据库
orderRepository.save(order);
// 扣减库存,更新商品数量等其他业务操作...
}
}
在上述代码中,OrderBO是一个业务对象,它封装了创建订单的业务逻辑。通过构造方法注入OrderRepository和ProductRepository,以便进行数据库操作。
createOrder方法接收用户对象和商品ID列表作为参数。它首先根据用户ID查询用户实体对象,然后根据商品ID查询商品实体对象。接下来,根据业务需求进行验证和处理,例如验证用户和商品是否有效。然后,创建订单对象并关联用户和商品信息。
最后,保存订单到数据库,并执行其他业务操作,比如扣减库存、更新商品数量等。
通过使用BO,可以将复杂的业务逻辑封装在一个独立的对象中,使代码更加清晰和可维护。BO负责处理具体的业务规则,协调多个领域对象之间的交互和操作,提供高层次的业务功能。这样可以降低模块间的耦合度,并使业务逻辑更易于理解和修改。
BO和service:
BO(Business Object)和Service都是在软件开发中常见的组件,用于处理业务逻辑。虽然它们的功能有一些重叠,但在实际应用中可以有不同的职责划分。
以下是一个简单的示例代码,展示了BO和Service之间的关系和用法:
public class OrderBO {
private OrderRepository orderRepository;
private ProductRepository productRepository;
public OrderBO(OrderRepository orderRepository, ProductRepository productRepository) {
this.orderRepository = orderRepository;
this.productRepository = productRepository;
}
// 创建订单的业务逻辑
public void createOrder(User user, List<Long> productIds) {
// 实现具体的业务逻辑...
}
// 取消订单的业务逻辑
public void cancelOrder(Long orderId) {
// 实现具体的业务逻辑...
}
}
@Service
public class OrderService {
private OrderBO orderBO;
public OrderService(OrderBO orderBO) {
this.orderBO = orderBO;
}
// 使用BO封装的业务逻辑创建订单
public void createOrder(User user, List<Long> productIds) {
// 调用BO执行具体的业务逻辑
orderBO.createOrder(user, productIds);
}
// 使用BO封装的业务逻辑取消订单
public void cancelOrder(Long orderId) {
// 调用BO执行具体的业务逻辑
orderBO.cancelOrder(orderId);
}
}
在上述代码中,OrderBO是一个业务对象,负责封装和处理订单相关的业务逻辑。它包含了创建订单和取消订单等具体的业务操作。
OrderService是一个服务类,使用@Service注解进行标识。它通过依赖注入方式获取到OrderBO对象,在方法中调用OrderBO的业务逻辑来实现具体的功能。Service类主要负责协调和组织不同的业务对象,提供高层次的业务功能接口。
通过将业务逻辑封装在BO中,可以将复杂的业务逻辑与底层细节分离,并提供可重用和可测试的组件。Service类作为业务逻辑的入口点,负责协调多个业务对象之间的交互,以及处理事务、异常等共通的操作。
需要注意的是,BO和Service的划分并没有严格的规定,可以根据具体项目的需求和设计原则进行灵活的组织和命名。重要的是根据职责单一原则来划分业务逻辑,使代码更清晰、可维护和可扩展。
PO(Persistant Object)持久对象
PO代表数据库中的持久化对象,它是与数据库表一一对应的Java对象。PO主要用于将数据从数据库中检索出来,并且可以进行持久化操作。
- 出现位置为数据库数据,用来存储数据库提取的数据
- 只存储数据,不包含数据操作
- 使用场景,在数据库层中,获取的数据库数据存储到PO中,然后转为DTO返回到服务层中
// ProductPO(持久化对象),与数据库表对应的Java对象。
@Entity
@Table(name = "products")
public class ProductPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal price;
// 省略getter和setter方法
}
DO(Domain Object,领域对象)
DO(Domain Object)指的是领域对象,它用于描述具体的业务领域概念,包含业务规则和行为。
DO 现在主要有两个版本:
- ①阿里巴巴的开发手册中的定义,DO( Data Object)这个等同于上面的PO
- ②DDD(Domain-Driven Design)领域驱动设计中,DO(Domain Object)这个等同于上面的BO
public class ProductDO {
private String name;
private BigDecimal price;
// 构造方法
public ProductDO(String name, BigDecimal price) {
this.name = name;
this.price = price;
}
// getter和setter方法
}
在上述代码中,ProductDO是一个领域对象,用于描述产品的相关属性。它通常包含与业务相关的数据和行为,例如名称、价格等。
通过定义DO对象,可以将业务概念和规则抽象化,并提供统一的接口进行操作和处理。
DO对象通常被BO或Service等组件使用,用于封装和处理具体的业务逻辑。
public class ProductService {
private ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public void createProduct(ProductDO productDO) {
// 根据业务需求进行验证和处理
// ...
// 创建新产品
ProductEntity productEntity = new ProductEntity();
productEntity.setName(productDO.getName());
productEntity.setPrice(productDO.getPrice());
// 保存产品到数据库
productRepository.save(productEntity);
// 其他业务操作...
}
}
在上述代码中,ProductService是一个服务类,负责产品相关业务的处理。它接收一个ProductDO对象作为参数,并根据业务需求进行验证和处理。
通过创建新的ProductEntity对象并设置相关属性,可以将DO对象转换为实体对象,并将其保存到数据库中。
通过使用DO对象,可以更加清晰地描述和处理具体的业务概念,使业务逻辑更易于理解和修改。DO对象通常与业务领域紧密相关,用于封装业务规则和行为,提供统一的抽象接口。
DO(Domain Object)对象通常由BO(Business Object)组件使用,用于封装和描述业务领域的概念和规则。BO负责协调多个领域对象之间的交互,并提供具体的业务操作和规则。
以下是一个简单的示例代码,展示了BO如何使用DO对象:
public class OrderBO {
private UserRepository userRepository;
private ProductRepository productRepository;
public OrderBO(UserRepository userRepository, ProductRepository productRepository) {
this.userRepository = userRepository;
this.productRepository = productRepository;
}
public void createOrder(OrderDO orderDO) {
// 根据订单信息查询用户DO对象和商品DO对象
UserDO userDO = userRepository.findById(orderDO.getUserId());
List<ProductDO> products = productRepository.findProductsByIds(orderDO.getProductIds());
// 验证用户和商品信息等业务逻辑处理
if (userDO == null || products.isEmpty()) {
throw new BusinessException("Invalid user or products");
}
// 创建订单并关联用户和商品
OrderEntity order = new OrderEntity();
order.setUser(userDO.toEntity()); // 调用DO对象的转换方法
order.setProducts(products.stream().map(ProductDO::toEntity).collect(Collectors.toList()));
// 保存订单到数据库
orderRepository.save(order);
// 其他业务操作...
}
}
在上述代码中,OrderBO是一个业务对象,它接收一个OrderDO对象作为参数并执行创建订单的业务逻辑。
首先,根据订单信息中的用户ID和商品ID查询对应的DO对象。然后,根据业务需求进行验证和处理,例如验证用户和商品是否有效。
接下来,通过创建OrderEntity对象,并使用DO对象的转换方法将相关属性转换为实体对象。最后,将订单实体对象保存到数据库中。
通过使用DO对象,BO可以更好地组织和封装业务逻辑,并与领域对象进行交互。DO对象负责描述具体的业务概念和规则,而BO负责协调和执行这些业务逻辑,使系统的设计更加清晰、可维护和易于扩展。
DO和DTO的区别
DO(Domain Object)和DTO(Data Transfer Object)是两种在软件开发中常见的对象,用于不同的目的和场景。
下面是DO和DTO之间的一般区别:
-
DO(Domain Object):
- DO主要用于表示具体的业务领域概念,包含了业务规则和行为。
- DO对象通常与业务逻辑紧密相关,用于封装和处理具体的业务领域概念。
- DO对象可能会包含复杂的业务逻辑和状态信息,以及对应的操作方法。
- DO对象通常由业务层或领域层使用,用于描述和处理具体的业务概念。
-
DTO(Data Transfer Object):
- DTO主要用于在不同层或模块之间传输数据。
- DTO对象通常是一个纯粹的数据容器,只包含属性和相关的getter和setter方法。
- DTO对象用于在不同层之间传递数据,以避免直接暴露底层实体对象,并简化数据传输和提高性能。
- DTO对象通常根据特定需求而创建,将多个数据项打包到一个对象中,方便在不同模块或者服务之间进行传递。
需要注意的是,DO和DTO的具体含义和用法可能会根据不同的项目、框架或团队而有所差异。在实际开发中,根据设计原则和具体需求来选择合适的对象,并根据业务场景进行适当的命名和使用方式。一般情况下,DO用于封装复杂的业务逻辑和领域概念,而DTO用于数据传输和跨层间的数据封装。
下面是一个示例代码,展示了如何结合使用VO(Value Object)、BO(Business Object)、PO(Persistent Object)、DO(Domain Object)和DTO(Data Transfer Object):
// VO(Value Object)
public class ProductVO {
private String name;
private BigDecimal price;
// 构造方法、getter和setter方法
}
// BO(Business Object)
public class ProductService {
private ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public ProductVO getProductById(Long id) {
// 查询PO对象
ProductPO productPO = productRepository.findById(id);
// 创建DO对象并设置属性
ProductDO productDO = new ProductDO();
productDO.setName(productPO.getName());
productDO.setPrice(productPO.getPrice());
// 调用其他业务逻辑处理DO对象
// ...
// 创建VO对象并设置属性
ProductVO productVO = new ProductVO();
productVO.setName(productDO.getName());
productVO.setPrice(productDO.getPrice());
return productVO;
}
}
// PO(Persistent Object)
@Entity
@Table(name = "products")
public class ProductPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "price")
private BigDecimal price;
// 构造方法、getter和setter方法
}
// DO(Domain Object)
public class ProductDO {
private String name;
private BigDecimal price;
// 构造方法、getter和setter方法
}
// DTO(Data Transfer Object)
public class ProductDTO {
private String name;
private BigDecimal price;
// 构造方法、getter和setter方法
}
在上述代码中,ProductVO是值对象,用于封装产品的展示数据。ProductBO是业务对象,负责协调和处理产品相关的业务逻辑。ProductPO是持久化对象,映射到数据库表结构。ProductDO是领域对象,用于描述具体的业务概念和规则。ProductDTO是数据传输对象,用于在不同层之间传输数据。
在ProductService的getProductById方法中,首先查询数据库获得ProductPO对象。然后,创建ProductDO对象并设置属性,调用其他业务逻辑处理DO对象。接下来,创建ProductVO对象并设置属性,将DO对象的属性赋值给VO对象。最后,返回ProductVO对象。
通过使用VO、BO、PO、DO和DTO等不同的对象,可以更好地组织和封装业务逻辑,并实现数据传输和业务处理的分离。VO用于传递展示数据,BO负责协调和处理业务逻辑,PO映射数据库表结构,DO描述具体的业务概念和规则,DTO用于在不同层之间传输数据。这种组合方式能提高代码的可读性、可维护性和可扩展性,同时降低模块之间的耦合度。
不同复杂度业务的实际运用:
不同复杂度的业务可以根据需求和设计原则来选择合适的对象和组件。下面是一种常见的实践方式:
-
对于简单的业务场景:
- 使用DTO(Data Transfer Object)来传输数据,将相关属性打包到DTO对象中,用于在不同层之间进行数据传输。
- 使用VO(Value Object)来封装展示层或前端页面需要的数据,以方便数据展示和交互。
- 使用PO(Persistent Object)来映射数据库表结构,与数据库进行交互,进行增删改查等持久化操作。
例如,一个简单的用户注册功能可以使用DTO作为数据传输对象,在不同层之间传递用户的注册信息;同时,使用VO将用户信息封装成可供前端展示的格式。
-
对于中等复杂度的业务场景:
- 使用BO(Business Object)来封装和处理复杂的业务逻辑,负责协调多个领域对象的交互,并提供具体的业务操作和规则。
- 使用PO(Persistent Object)来映射数据库表结构,与数据库进行交互,进行增删改查等持久化操作。
例如,一个电商平台的订单管理模块可能涉及到处理订单状态、库存检查、支付验证等多个业务操作,这时可以使用BO来封装这些复杂的业务逻辑,并使用PO与数据库进行交互。
-
对于更复杂的业务场景:
- 使用DO(Domain Object)来描述具体的业务领域概念,包含业务规则和行为。
- 使用Service实现类来协调各个对象之间的交互和操作,提供具体的业务功能接口。
例如,在一个金融系统中,涉及到复杂的财务计算、风险评估等业务逻辑,可以使用DO来描述这些领域概念和规则,并使用Service实现类来组织和管理业务逻辑的执行。
需要注意的是,上述划分只是一种常见的实践方式,并不是固定的规则。在实际开发中,根据具体的需求、项目架构和团队约定,可以灵活选择和组合这些对象和组件来满足业务的复杂度和可维护性的要求。
示例代码
Controller层
此层常见的转换为:DTO转VO,将Services层传过来的DTO转换成VO表示数据返回给前端
public List<UserVO> getUsers(UserQuery userQuery);
Service层、Manager层:
此层常见的转换为:DO转BO、BO转DTO
// 普通的service层接口,对数据处理,返回DTO对象
List<UserDTO> getUsers(UserQuery userQuery);
然后在Service内部使用UserBO封装中间所需的逻辑对象
DAO层
此层常见的转换为:DTO转换为DO,与数据库进行交互
List<UserDO> getUsers(UserQuery userQuery);
领域模型定义
- Entity表结构实体,对应DO
- BO业务实体
- VO视图实体,DTO可共用
- 入参封装
○ xxxParam
○ Query xxx Param
○ Save xxx Param
○ Edit xxx Param
○ Remove xxx Param
IDEA插件完成转换
插件名称:Simple Object Copy
- 定义方法出入参,出入参就是要转换的实体
- 光标定位方法内,使用快捷键ALT+INSERT(WIN) 、 command + N(mac) ,或者右键鼠标选择Generate,弹出生成选项框后,选择genCopyMethod,代码就生成好了
复杂对象也可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?