# 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对象而不是实体对象，从而提高系统的一致性和性能。

本报告为后续的子任务提供了具体的修改依据，帮助确定具体的实现方案和步骤。