3

我正在尝试在我当前的项目中应用 DDD 的原理。我将尝试用一个希望有意义的例子来问这个(冗长的)问题。

创建新成员时,我的表示层调用在应用层中定义的 MemberService.CreateMember(MemberDTO memberDTO)。

我的表示层有这样的东西:

MemberDTO member = new MemberDTO(); //Defined in Application Layer

member.Username = username;
member.Password = password;
//...etc

我的应用程序层在域层中调用以下工厂方法来创建成员:

public static Member MemberFactory.CreateMember(string memberDTO.Username, string memberDTO.Password...)
{
  var member = new Member(); //Domain.Model.Member

  member.Id = GenerateIdentity();

  member.Username = memberDTO.Username;

  //... etc

  return member;
}

成员被传递回 MemberService(应用程序层),后者保存它(基础设施层中的存储库)并将其映射到 MemberDTO(使用 AutoMapper)并将其传递回表示层。

因此,我的表示层在 MemberDTO 中设置值,然后我的域层(通过工厂)获取单个参数并为成员设置值。如果没有工厂,它会很简单,但我在这里生成 Id。创建域服务而不是生成 Id 会不会是错误的?例如,将 MemberService.CreateMember(MemberDTO memberDTO) 方法从:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   var member = MemberFactory.CreateMember(memberDTO.Username, memberDTO.Password); 
   //Domain.Model.Member

   SaveMember(member);

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

对此:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   var member = new Member(); //Domain.Model.Member

   Mapper.Map<MemberDTO, Member>(memberDTO);

   //Add this method into a Domain Service to generate the ID and any other defaults
   Domain.MemberService.Initialise(member);

   SaveMember(member);

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

很抱歉这个冗长的问题,即使答案可能是简单的是或否!

4

3 回答 3

2

关于 DDD,如果此身份不是域身份(即基于有界上下文定义用户的内容),那么它不属于您的域模型。在我见过的大多数情况下,用户名是有界上下文中用户的身份,并且任何生成的 ID 都是为了访问数据库而完成的。我怀疑这可能是您的情况,如果我是对的,那么生成的 ID 是基础架构问题,应该由您的存储库实现来完成。您的域不应该有这个生成的 ID 的任何概念。

另一方面,假设用户名是您上下文中用户的身份,并且您希望使用某些域公式生成该身份。在这种情况下,生成身份将是一种域服务方法,因为它实际上并不属于任何域对象的实例。然后生成的 ID 将被传递到您的工厂,您将拥有:

public MemberDTO CreateMember(MemberDTO memberDTO)
{
   //Domain.Model.Member
   var member = MemberFactory.CreateMember(MemberService.GenerateUserName(), memberDTO.Password); 

   SaveMember(member); //Repository method?

   //Pass DTO to presentation layer
   return Mapper.Map<Member, MemberDTO>(member);
}

总而言之,答案是否定的,假设 ID 是有界上下文的实际身份,创建域服务来生成 ID 并没有错。事实上,这是你应该做的。但是,如果 ID 不是有界上下文的用户身份,那么让您的存储库担心如何生成 ID、访问数据库以及与域模型之间进行转换。

于 2013-01-02T15:04:39.647 回答
1

简短的回答:是的,您可以将 DTO 对象传递给工厂。

长答案:域对象工厂负责创建完全初始化的域对象。但是,只要您能提供所需的信息,您就可以自由选择任何形式的输入。在这种情况下,在您的工厂中使用任一方法是个人选择的问题: - public Member CreateMember(string userName, string password, ...) {...} - public Member CreateMember(MemberDTO memberDTO) {.. .}

从分层的角度来看,域对象工厂是域模型的一部分。因此,它可以被领域模型层和应用层中的不同对象使用和依赖。根据您的描述, MemberService 似乎属于您的应用程序(服务)层。如果将创建逻辑移入其中,您可能会发现困难的依赖问题。例如,如果一个 Booking 域对象在确认时创建了一个 Member 域对象,那么您最终可能会使 Booking 对象依赖于 MemberService,这不是一个好主意。示例如下所示:http: //thinkinginobjects.com/2012/09/05/abstract-factory-in-domain-modelling

如果我们退后一步,从某个角度看问题,我想问一下 MemberDTO 和 MemberService 究竟为您的应用程序提供什么服务。DTO 对象是否用作一组数据字段的包装器?MemberService 是否只是将 create 调用委托给您的工厂和存储库?如果答案是肯定的,那么如果我们一起摆脱 MemberDTO 和 MemberService 并让演示文稿直接调用 MemberFactory 和 MemberRepository,代码会简单得多。我在这里做了很多假设,但是如果您的表示层和服务层在物理上是分开的,您可能会发现 DTO 和服务仍然是可取的。

于 2013-01-02T22:53:37.497 回答
1

我不确定这个问题与 DDD 的关系,因为我没有看到需要额外复杂性的复杂域。但是,可能有一个论点是在另一个结构中定义身份的生成,但这主要是为了实现单一职责(SRP)。

我建议您创建一个名为IGenerateMemberIdentity. 然后,您可以隔离该复杂性并对其进行测试。我认为您认为此功能不属于工厂的直觉是正确的。如果这是一个复杂的例程,它似乎与对象创建无关。

然而,对我来说,Initialize静态方法似乎是一种代码味道。最好在提供该功能的接口后面注入依赖项。

专门回答你的问题。不,我不认为这是错误的。事实上,为了保留纯业务功能而对复杂性进行建模是 DDD 最擅长的。

于 2013-01-01T18:00:31.587 回答