DDD - injecting Factories in aggregate root Entity constructor

1.7k Views Asked by At

I'm writing an app with DDD in mind and trying to avoid having an anemic domain model by delegating doman logic and behaviour to entities. There's an issue I'm running into with constructing entities that are aggregate roots and need to create sub-entities that require handling by a factory class. Here's an example:

I have the following entities: Page, Url and Layout. What makes a Page in my model is a Page with a Url and a Layout - without those two, a Page object would not be valid. In a simple model, the Page constructor method would simply create those two objects as private attributes. However, the Url has a specific requirement; it has to be created from the Page's title - or a slug - and it has to be unique (ensured by appending "-1", "-2", or something similar). This requires communication with a repository.

My initial idea was to pass/inject a UrlFactory object to the Page constructor and have the Page create the Url it needs, but I keep reading about how injecting services into entities is a bad idea.

So, my question is; is there a way - or an established pattern - to allow entities to construct their complex sub-entities without having an anemic domain model, or is injecting a factory in case such as this a valid solution?

2

There are 2 best solutions below

0
Dariss On

Do not inject factory class into aggregrate, use factory method instead. Then create method "validate(Validator)" in aggregate (Aggregate will only know it can be valided, but it will not implement logic how to do it).

Validator class which will be passed as parameter to your validate method, will need to have one method ->validateObject(this). You pass instance of aggregate into validateObject so it will have access to your properties.

Validator class can have injected repository. When you run validateObject method it will search database for uniquness.

2
guillaume31 On

If you consider URL construction as a technical concern, you could have an UrlFactory in the Infrastructure layer

in C# :

public class UrlFactory 
{
  public string CreateUrl(string title)
  {
    var url = // ... construct URL from the title here

    return _pageRepository.NextAvailableUrlLike(url);
  }
}

and then call it from your Application layer service.

If you see it as a Domain concern, Url construction logic could be in a Domain Service instead. The line calling the repository would be moved to the Application layer Service :

public void CreatePage(string title)
{
  var potentialUrl = _urlService.CreateUrl(title);
  var realUrl = _pageRepository.NextAvailableUrlLike(url)
  new Page(title, realUrl, ...); // do whatever you want with the new Page instance
}