8

Ok i read many things about the repository pattern, including Fowler's book. I know pretty good what it is and what it does, however what i'm not quite sure yet is how it is called by factories and/or domain objects.

What I understood is that the repository is supposed to act like an in-memory collection of domain object, and the factory is the class in charge of the instance creation: new myDomainObject()

With that in mind, it seems obvious that the repository will need a reference to the factory to create new objects from the data source queries. (Repository -> Factory)

Domain objects also need a reference to the factory in order to create new objects.

My dilemma is when a domain object want to retreive an existing object, should it call the repository or the factory ? If it calls the repository directly (Domain -> Repository -> Factory), than it would need to have both the references to the factory and the repository, which seems too much to me, but is it that bad ?

On the other hand, if it calls the factory like factory.CreateObjectWithId(id), then the factory would have to only redirect the call to the repository repository.GetById(id), and this last would call another method on the same factory for object creation (if it is not already in memory) factory.CreateObject(dataset), so that leads to a circular reference: Domain object -> Factory <--> Repository, which again does not seems really a good thing to me.

So in your opinion which of these options is better ? or is there another option ?

JuanZe
  • 8,007
  • 44
  • 58
Jonathan
  • 1,276
  • 10
  • 35

1 Answers1

7

You've got the basics right. The misunderstanding you have seems to come from your assumption that domain objects should be the primary clients of repositories. This is not the case, you should only access the repositories from domain objects if there is no other way. Try to avoid it in general.

So the missing piece in your equation is the thing that acts as primary client of the repositories.

Enter: The Application Service

An application service is a service that contains use case logic (as opposed to domain logic). It performs input validation, implements access management, and is responsible for transaction control.

This means the app service would use a repository to load an aggregate from the DB, do something with it, and then make sure the changes are persisted (i.e. commit the transaction).

Depending on the style of repository that you're using, saving an aggregate back to the DB is slightly different:

  • With collection-style repositories, the app service normally uses a unit of work to track and commit the changes.
  • With command-style repositories, the app service passes the aggregate back to the repository after performing the business operation on it.

Factories and Repositories

Regarding your questions about the relationship between factories and repositories, I think this answer of mine provides the answer to your question as well. The basic gist of it is:

  • Use the factory from the repository to avoid duplicating the instantiation logic of an aggregate.
  • Make sure the concepts are clear from the outside, i.e. don't expose the "reconsitution interface" of a factory that the repository sees to other classes. This is best achieved by following the Interface Segregation Principle.

Using Repositories from the Domain

If you constantly need to query other aggregates from the DB to perform business tasks in the domain layer, this is an indication that your aggregate boundaries could be wrong.

Of course, there are cases where the aggregate boundaries are fine, and the required objects cannot be passed to the domain object as parameter. In that case, it can make sense to use a repository from the domain. Be sure to try other approaches before doing this. In any case, only depend on a repository interface, never on a concrete repository implementation.

Community
  • 1
  • 1
theDmi
  • 17,546
  • 6
  • 71
  • 138
  • Very well explained! thanks a lot. I guess I should buy a copy of Evans' book ;) – Jonathan Dec 16 '15 at 18:35
  • Your saying to avoid calling repository from domain object in general, that the application service should generally do it. I kinda agree with you, but what about aggregate roots (these are not the "application service" right ?) and also the fact that many are saying that the repository interface belongs to the domain layer ? – Jonathan Dec 17 '15 at 18:57
  • @Jonathan If you avoid repo calls from within the domain, your domain model will become easier to reason about. After all, a repository is not a term from your domain. I'd always try to pass in the required data from an app service, but of course there are cases where you need to access a repo from an aggregate or domain service. – theDmi Dec 18 '15 at 07:49
  • Aggregate roots are just entities with additional responsibilities, so they are part of the domain. Application services live *outside* the domain. – theDmi Dec 18 '15 at 07:52
  • What could justify the use of a repository from the inside of a domain object ? lazy loading ? – Jonathan Dec 29 '15 at 16:30