Files
contract-manager/docs/task/server模块service缓存调整为Vo对象/ANALYSIS_service_class_patterns.md
songqq 49413ad473 refactor(service): 统一Service缓存为VO对象并优化关联实体处理
重构Service类实现,将QueryService泛型参数调整为VO类型,确保缓存VO对象而非实体。优化关联实体处理逻辑,减少重复代码。修改findById方法返回VO对象,新增getById方法获取实体。更新相关调用点以适配新接口。

调整WebSocket处理、控制器及Service实现,确保数据类型一致性。完善文档记录重构过程及发现的问题。为后续优化提供基础架构支持。
2025-09-29 19:31:51 +08:00

178 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Service类结构模式分析报告
## 1. 概述
本报告是"实体-VO转换机制与缓存策略任务拆分"子任务1的延伸分析旨在详细分析Contract-Manager项目中Service类的实现模式特别是QueryService接口泛型参数的使用情况为将Server模块Service缓存从实体对象调整为VO对象提供具体的修改依据。
## 2. Service类实现模式分析
通过对Server模块中Service类的分析发现了两种主要的实现模式
### 2.1 模式一正确实现模式VO优先
这种模式下Service类实现QueryService接口时使用VO类型作为泛型参数符合项目设计理念。
**示例代码:**
```java
@Service
@CacheConfig(cacheNames = "inventory")
public class InventoryService
implements IEntityService<Inventory>, QueryService<InventoryVo>, VoableService<Inventory, InventoryVo> {
// Service方法实现
}
@Service
@CacheConfig(cacheNames = "function")
public class FunctionService implements IEntityService<Function>, QueryService<FunctionVo>, VoableService<Function, FunctionVo> {
@Cacheable(key = "#p0")
public FunctionVo findById(Integer id) {
return repository.findById(id).map(Function::toVo).orElse(null);
}
}
```
**特点:**
1. QueryService接口使用VO类型作为泛型参数
2. findById等缓存方法返回VO对象
3. findAll方法通常使用map(Entity::toVo)转换为VO对象
4. 缓存的是VO对象符合设计要求
**采用此模式的Service类**
- InventoryService
- ProjectQuotationService
- FunctionService
- DepartmentService
- BankService
- ContractBidVendorService
- ProjectIndustryService
- ProjectBidService
- ProjectFundPlanService
- InventoryHistoryPriceService
- ProjectTypeService
- PermissionService
- ProjectCostItemService
- EmployeeRoleService
- CustomerSatisfactionSurveyService
### 2.2 模式二:错误实现模式(实体优先)
这种模式下Service类实现QueryService接口时使用实体类型作为泛型参数不符合项目设计理念。
**示例代码:**
```java
@Service
@CacheConfig(cacheNames = "company")
public class CompanyService extends EntityService<Company, Integer>
implements IEntityService<Company>, QueryService<Company>, VoableService<Company, CompanyVo> {
// Service方法实现
}
@Service
public class CompanyBlackReasonService implements IEntityService<CompanyBlackReason>, QueryService<CompanyBlackReason>,
VoableService<CompanyBlackReason, CompanyBlackReasonVo> {
// Service方法实现
}
```
**特点:**
1. QueryService接口使用实体类型作为泛型参数
2. findById等缓存方法返回实体对象
3. 缓存的是实体对象,不符合设计要求
4. 虽然同时实现了VoableService接口但转换逻辑与缓存逻辑分离
**采用此模式的Service类**
- CompanyService
- CompanyBlackReasonService
- ContractPayPlanService
- CompanyOldNameService
- CompanyCustomerEntityService
- ContractCatalogService
- CompanyInvoiceInfoService
- CompanyExtendInfoService
## 3. WebSocketServerCallbackManager分析
WebSocketServerCallbackManager类负责处理客户端与服务器之间的WebSocket通信包括对查询服务的调用处理
```java
private Object invokerFindByIdMethod(Object service, JsonNode argumentsNode) {
JsonNode paramsNode = argumentsNode.get(0);
if (service instanceof IEntityService<?> entityService) {
Integer id = paramsNode.asInt();
return entityService.getById(id);
}
// 其他实现...
}
private Object invokerFindAllMethod(Object service, JsonNode argumentsNode) throws JsonProcessingException {
JsonNode paramsNode = argumentsNode.get(0);
JsonNode pageableNode = argumentsNode.get(1);
PageArgument pageArgument = objectMapper.treeToValue(pageableNode, PageArgument.class);
QueryService<?> entityService = (QueryService<?>) service;
Page<?> page = entityService.findAll(paramsNode, pageArgument.toPageable());
return PageContent.of(page.map(entity -> {
if (entity instanceof Voable<?>) {
return ((Voable<?>) entity).toVo();
}
return entity;
}));
}
```
**关键点:**
1. invokerFindByIdMethod直接返回实体对象没有进行VO转换
2. invokerFindAllMethod在返回前会尝试将实体转换为VO
3. 这种不一致的处理方式可能导致客户端接收的数据类型不一致
## 4. 缓存策略分析
### 4.1 正确的缓存策略(模式一)
```java
@Cacheable(key = "#p0")
public FunctionVo findById(Integer id) {
return repository.findById(id).map(Function::toVo).orElse(null);
}
```
**特点:**
1. 缓存方法直接返回VO对象
2. 在缓存方法内部完成实体到VO的转换
3. 缓存的是VO对象符合设计要求
### 4.2 错误的缓存策略(模式二)
```java
@Cacheable(key = "#id")
public Contract findById(Integer id) {
// 直接返回实体对象
}
```
**特点:**
1. 缓存方法返回实体对象
2. 缓存的是实体对象,不符合设计要求
3. 客户端可能需要额外的转换步骤
## 5. 需要修改的Service类清单
基于以上分析以下是需要修改的Service类清单
| Service类名 | 问题 | 修改建议 |
|------------|------|---------|
| CompanyService | QueryService使用实体类型 | 将QueryService<Company>改为QueryService<CompanyVo> |
| CompanyBlackReasonService | QueryService使用实体类型 | 将QueryService<CompanyBlackReason>改为QueryService<CompanyBlackReasonVo> |
| ContractPayPlanService | QueryService使用实体类型 | 将QueryService<ContractPayPlan>改为QueryService<ContractPayPlanVo> |
| CompanyOldNameService | QueryService使用实体类型 | 将QueryService<CompanyOldName>改为QueryService<CompanyOldNameVo> |
| CompanyCustomerEntityService | QueryService使用实体类型 | 将QueryService<CompanyCustomerEntity>改为QueryService<CompanyCustomerEntityVo> |
| ContractCatalogService | QueryService使用实体类型 | 将QueryService<ContractCatalog>改为QueryService<ContractCatalogVo> |
| CompanyInvoiceInfoService | QueryService使用实体类型 | 将QueryService<CompanyInvoiceInfo>改为QueryService<CompanyInvoiceInfoVo> |
| CompanyExtendInfoService | QueryService使用实体类型 | 将QueryService<CompanyExtendInfo>改为QueryService<CompanyExtendInfoVo> |
## 6. 结论
通过对Service类实现模式的详细分析我们明确了需要修改的Service类清单和具体的修改建议。这些修改将有助于统一Service类的实现模式确保缓存的是VO对象而不是实体对象从而提高系统的一致性和性能。
本报告为后续的子任务提供了具体的修改依据,帮助确定具体的实现方案和步骤。