Service 是领域服务层,用于实现业务逻辑。在 Freedom 框架中,Service 的定义和使用非常简单:
// 定义 Service
type DefaultService struct {
Worker freedom.Worker // 依赖注入请求运行时
DefRepo *repository.Default // 依赖注入资源库对象
DefRepoIF repository.DefaultRepoInterface // 也可以注入资源库接口
}
// 实现业务方法
func (s *Default) RemoteInfo() (result struct {
IP string
Ua string
}) {
s.Worker.Logger().Info("I'm service")
result.IP = s.DefRepo.GetIP()
result.Ua = s.DefRepoIF.GetUA()
return
}
Service 需要在 init() 函数中注册到框架:
func init() {
freedom.Prepare(func(initiator freedom.Initiator) {
// 绑定创建服务函数到框架
initiator.BindService(func() *DefaultService {
return &DefaultService{}
})
// 注入到控制器
initiator.InjectController(func(ctx freedom.Context) (service *DefaultService) {
initiator.FetchService(ctx, &service)
return
})
})
}
Freedom 框架支持多种依赖注入方式:
每个 Service 可以注入 Worker 对象,用于获取请求上下文、日志等:
type UserService struct {
Worker freedom.Worker // 运行时,一个请求绑定一个运行时
}
func (s *UserService) SomeMethod() {
// 使用 Logger
s.Worker.Logger().Info("some log")
// 获取上下文
ctx := s.Worker.IrisContext()
}
Service 可以注入 Repository 对象或接口:
type OrderService struct {
OrderRepo dependency.OrderRepo // 依赖倒置订单资源库
GoodsRepo dependency.GoodsRepo // 依赖倒置商品资源库
}
可以注入 Factory 用于创建聚合根等:
type GoodsService struct {
ShopFactory *aggregate.ShopFactory // 依赖注入购买聚合根工厂
}
可以注入基础设施组件:
type UserService struct {
Transaction transaction.Transaction // 依赖注入事务组件
CartFactory *aggregate.CartFactory //依赖注入购物车聚合根工厂
}
Freedom 提供了事务组件用于保证数据一致性:
type OrderService struct {
Transaction transaction.Transaction //事务组件
}
// 简单事务示例
func (srv *OrderService) CreateOrder() error {
return srv.Transaction.Execute(func() error {
// 在这个闭包函数中的所有数据库操作都在同一个事务中
if err := srv.OrderRepo.Create(); err != nil {
return err // 返回错误会触发回滚
}
return nil // 返回 nil 会提交事务
})
}
// 复杂业务事务示例
func (srv *OrderService) Shop(goodsID, num, userID int) error {
goodsEntity, err := srv.GoodsRepo.Get(goodsID)
if err != nil {
return err
}
if goodsEntity.Stock < num {
return errors.New("库存不足")
}
goodsEntity.AddStock(-num) // 扣减库存
// 使用事务保证一致性:
// 1. 修改商品库存
// 2. 创建订单
return srv.Transaction.Execute(func() error {
if err := srv.GoodsRepo.Save(goodsEntity); err != nil {
return err
}
return srv.OrderRepo.Create(goodsEntity.ID, num, userID)
})
}
通过工厂和聚合的合理使用,可以使 Service 层的代码更加清晰和易于维护。同时遵循 CQS 原则,也使系统行为更加可预测。DDD 指南 - 工厂
// 购买商品使用工厂的示例
func (s *CartService) Shop(ctx context.Context, cartID string) error {
// 使用工厂创建购买命令
cmd, err := s.CartFactory.CreateShopCmd(cartID)
if err != nil {
return err
}
// 执行购买操作
return cmd.Run()
}
// 查询商品使用工厂的示例
func (s *CartService) GetCartDetail(ctx context.Context, cartID string) (*dto.CartDetail, error) {
// 创建查询
query := s.CartFactory.CreateDetailQuery(cartID)
// 执行查询并返回结果
return query.Result()
}
- 事务会自动处理回滚,在 Execute 闭包中返回 error 会触发回滚
- 事务中的所有数据库操作都会使用同一个事务连接
- 事务结束后会自动提交或回滚
- 事务支持嵌套使用
- 事务中可以结合领域事件使用
- Service 职责单一,只实现特定领域的业务逻辑
- 通过依赖注入解耦各个组件
- 合理使用事务保证数据一致性
- 使用 Worker 处理日志、上下文等
- 遵循 DDD 设计原则,合理划分领域边界
- Service 依赖字段必须是公开的(首字母大写),以便框架注入