Dependencies between domain object, factory and re

2019-01-24 11:51发布

问题:

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 ?

回答1:

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.