引言
在构建现代Web应用时,服务层(Service Layer)作为业务逻辑的核心载体,其设计质量直接影响系统的可维护性和扩展性。今天我将分享关于ChatService服务层的设计思考,重点探讨如何通过职责分离和依赖注入构建高内聚、低耦合的业务逻辑层。

服务层的核心职责
一个良好设计的ChatService应该保持明确且专一的职责边界:

  1. 请求处理:接收前端提交的问题/请求
  2. 业务协调:调用大模型API进行智能处理
  3. 数据格式化:将原始响应转换为前端友好的结构
  4. 持久化:保存聊天记录到数据库
public class ChatService {
    // 服务方法示例
    public ChatResponse processUserQuery(UserQuery query) {
        // 1. 参数校验与预处理
        // 2. 调用大模型API
        // 3. 格式化响应
        // 4. 保存聊天记录
        // 5. 返回处理结果
    }
}

关键设计原则:服务层不应涉及
• HTTP请求/响应处理(Controller的职责)
• 直接数据库操作(Mapper/Repository的职责)
• 前端视图渲染(View层的职责)

依赖注入:松耦合的关键
@Autowired的工作原理
Spring框架通过@Autowired实现控制反转(IoC):

@Service
public class ChatService {
    private final BigModelService bigModelService;
    private final MessageMapper messageMapper;
    
    @Autowired
    public ChatService(BigModelService bigModelService, 
                      MessageMapper messageMapper) {
        this.bigModelService = bigModelService;
        this.messageMapper = messageMapper;
    }
}

构造器注入的优势

  1. 不可变依赖:final字段确保依赖关系在构造后不再改变
  2. 明确依赖:创建对象时即明确所有必需依赖
  3. 避免NPE:防止因依赖未注入导致的空指针异常
  4. 测试友好:便于在单元测试中注入mock对象

依赖注入带来的灵活性
当需要更换大模型供应商时:

// 只需新增实现类
@Service
public class GPT4Service implements BigModelService {
    // 实现细节
}

// 通过配置切换实现
@Configuration
public class ModelConfig {
    @Bean
    public BigModelService bigModelService() {
        return new GPT4Service(); // 或原来的BigModelNew
    }
}

服务层设计最佳实践

  1. 单一职责原则:每个服务类/方法只做一件事
  2. 接口隔离:依赖抽象而非具体实现
  3. 异常处理:在服务层统一处理业务异常
  4. 事务管理:使用@transactional确保数据一致性
  5. 日志记录:关键操作添加适当的日志
@Service
@Transactional
public class ChatServiceImpl implements ChatService {
    
    private static final Logger logger = LoggerFactory.getLogger(ChatServiceImpl.class);
    
    @Override
    public ChatResponse processQuery(UserQuery query) {
        try {
            // 业务逻辑
        } catch (BusinessException e) {
            logger.error("Process query failed", e);
            throw new ServiceException("处理请求失败", e);
        }
    }
}

单元测试示例
利用Mockito测试服务层:

@ExtendWith(MockitoExtension.class)
class ChatServiceTest {
    
    @Mock
    private BigModelService bigModelService;
    
    @Mock
    private MessageMapper messageMapper;
    
    @InjectMocks
    private ChatService chatService;
    
    @Test
    void shouldProcessQuerySuccessfully() {
        // 准备测试数据
        UserQuery query = new UserQuery("Hello");
        ModelResponse mockResponse = new ModelResponse("Hi there");
        
        // 定义mock行为
        when(bigModelService.callModel(any())).thenReturn(mockResponse);
        
        // 执行测试
        ChatResponse result = chatService.processQuery(query);
        
        // 验证结果
        assertEquals("Hi there", result.getContent());
        verify(messageMapper).insert(any(Message.class));
    }
}