在有些情况下,根据我们的业务领域和管理规则,有些概念不能作为现有实体的一部分进行建模;在这些情况下,就需要引入服务。
尽管这是一个真正的超载术语,但在领域驱动设计的背景下,服务以特定的有边界的上下文的泛在语言来定义断言。
在领域驱动设计中,无处不在的语言被Eric Evans定义为。
一种围绕领域模型结构化的语言,由所有团队成员在一个有边界的上下文中使用,将团队的所有活动与软件联系起来。
而有边界的上下文是指。
对一个边界(通常是一个子系统,或一个特定团队的工作)的描述,在这个边界内,一个特定的模型被定义并适用。
一个服务在实践中是怎样的?
如果我们看一下我们的 "To Do Microservice "的代码,我们实现了一个 service.Task这看起来像。
// Task defines the application service in charge of interacting with Tasks.
type Task struct {
repo TaskRepository
}
// Create stores a new record.
func (t *Task) Create(ctx context.Context, description string, priority internal.Priority, dates internal.Dates) (internal.Task, error) { /* ... */ }
// Task gets an existing Task from the datastore.
func (t *Task) Task(ctx context.Context, id string) (internal.Task, error) { /* ... */ }
// Update updates an existing Task in the datastore.
func (t *Task) Update(ctx context.Context, id string, description string, priority internal.Priority, dates internal.Dates, isDone bool) error { /* ... */ }
这个服务引用了一个名为TaskRepository 的资源库,这个资源库最终通过main中的 依赖注入(Dependency Injection)被分配。
这种形式的服务通常代表聚合(Aggregates),最终是为了代表一个领域对象的集群,被视为一个单一的单元。在这段代码的未来迭代中,我们将看到当任务还包括其他东西如SubTasks 和Categories 时,这一点是如何到位的。
总结
实现服务对于表明领域对象和一些外部依赖关系(如持久层)之间的交互是非常有用的。实现服务的一个困难之处在于,要知道什么时候应该实现这些服务,要确定我们应该考虑那些我们的业务有特定流程应该被建模为一个单元的情况。
尽管在我们的 "待办项目 "中,我们使用Task 作为服务名称,这意味着不是数据库表或模型任务,而是与任务和其他实体互动的过程,所有这些都被作为一个单一的东西来处理。
当定义服务时,用这些术语来思考,问 "我们试图建模的业务流程是什么,哪些实体应该参与?"回答了这个问题,你就应该知道我们可以作为服务建模的过程的名称。