4

I have a relatively simple domain model, as shown by the diagram. I would like to maintain this logic within my domain objects as defined by DDD.

Each domain object is an abstract class which only contains its respective members and domain logic. Concrete implementations of these classes are returned by the repositories, supplied to the service (with DI).

What I am having trouble with is understanding how to deal with the situation that I need to create a new entity. For example the domain logic dictates:

An account can be added to a Group (creating a Member entity).

  • When an account is added to a group, the new Member entity's Value property must be set to the total number of members that are already in the Group.

  • Every other member of the Group must have their value incremented by 1.

I could implement this as a Member AddMember(Account account) method on Group. However this method will somehow need to instantiate a new Member to add to the Group's Members collection.

As the domain object's have no references to the layers further up in the application, and the domain objects themselves are abstract, I'm unsure how to go about constructing the new instance of Member.

I have considered the possibility of defining an abstract protected Member CreateMember() method on the Group object that concrete implementations can implement but this seems messy to me and concerns me that I may be misunderstanding something more fundamental.

While trying to stay true to DDD principles, how would I go about implementing this model?

Domain Entity Diagram

Sam Greenhalgh
  • 5,952
  • 21
  • 37

2 Answers2

2

You probably want to create a MemberFactory (as a Domain Service) that has the responsibility of creating new Member objects. See this answer for a great example.

Community
  • 1
  • 1
Steve Czetty
  • 6,147
  • 9
  • 39
  • 48
1

I think the fundamental issue here is the fact that your domain objects are abstract. Domain objects should almost always be concrete classes (though there are a few exceptions) that implement all the necessary domain logic.

A repository is simply an interface to an external data source (such as a database) and shouldn't affect how your domain works. By having the repository return the actual implementation of your objects, you are coupling domain logic with the repository.

You should rethink your design so that your entities are concrete classes. Together, your domain objects should implement all the domain logic without regard to external services / repositories.

casablanca
  • 69,683
  • 7
  • 133
  • 150
  • Thanks for answering. My understanding is that returning concrete objects allows me to implement behavior such as persistence or lazy loading without polluting the domain objects themselves. This doesn't seem to deviate from the proxy pattern that most ORMs use to implement repositories. In this scenario, I want to reduce the chance of instantiating a new domain object outside of the infrastructure and hence made the objects abstract. Passing factories in as well as repositories, as @Steve Czetty suggests would seem to be an acceptable solution. – Sam Greenhalgh Jul 16 '12 at 16:32
  • @SamGreenhalgh: Lazy loading can be implemented by injecting the repository interface into a concrete domain object. In fact, by making the classes abstract, you are actually polluting them more because the concrete implementation has to implement persistence as well as domain logic. – casablanca Jul 16 '12 at 17:01
  • Surly the domain logic is inherited from the abstract and as such doesn't need to (or can't if its not marked virtual) be implemented by the concrete implementation? Surly the domain object's shouldn't be implementing persistence, isn't that a concern of the infrastructure? What would happen in the case that I wanted to to change from say, using NHibernate to Entity Framework for persistence? – Sam Greenhalgh Jul 17 '12 at 01:18
  • @SamGreenhalgh: True, but this is a classic case of inheritance vs. composition and whether it makes sense to inherit to add persistence features (which are not related to the domain object). If you inject a repository *interface*, the domain object is independent of the *implementation* -- the actual repository implementation would inject itself into the domain object when loading it. – casablanca Jul 17 '12 at 07:04
  • Thanks for your responses, they've been very constructive. I've accepted Steve Czetty's answer as I've implemented factories which seems to be working effectively. – Sam Greenhalgh Jul 17 '12 at 15:49