Factory Pattern where should this live in DDD?
Asked Answered
W

6

15

I have debated this for a while now and still have not come to a conclusion. While most examples I see have the factories code in the application layer I tend to think it should be in the domain layer. Reasons for this: I sometimes have initial validation done in my factory where I want all creation of objects to go through. I want this code to be used on all instantiates of my object. Sometimes an operation requires parameter information which feels unnatural to pass to a constructor. And a few more not as important reasons.

Are there reasons why this is a bad practice? Does this break other patterns?

Westberry answered 10/12, 2012 at 16:16 Comment(0)
J
8

+1 for doing that. Accessibility would be a good reason, I would keep the creational code at least close to the domain model layer. Otherwise users of the domain model will get simply confused how to instantiate it specially when finding restricted access constructors. Actually one sound reason to separate it would be that you have different valid ways to create the same thing e.g. which is the case usually when employing the Abstract Factory.

If I had to separate it I would put it in e.g. a package (in the case of Java) at least the same level of the domain model and ship it always along with it e.g.

upper
  --> domain
  --> domain_factory
Jubbulpore answered 10/12, 2012 at 16:33 Comment(1)
It would appear most people agree with it being in the domain model. so then where do you recommend your Factories exist in the Domain layer? A separate assembly, folder, namespace?Westberry
J
12

A factory in DDD is just an instance of the factory pattern and as such it should be used where it makes the most sense. Another principle to consider is the information expert pattern which essentially states that behavior should be assigned to classes closest to the information. Therefore, if you have some domain specific rules and logic you would like to enforce, place the factory in the domain layer - after all, the factory creates domain objects. Note however that you may have other types of factories in other layers.

Josefjosefa answered 10/12, 2012 at 16:30 Comment(1)
Exactly, the principle of information expert guides the placement by "where information is to fulfill the responsibility". For object-creation, the model-related information may be in the model-layer, whereas other types of factories should be near other layers, such as REST- or web-layer, which can create representation based on the information such as Mime-Types, etc.Seavir
U
8

From memory, Eric Evans' book has examples where object factories are very much part of the domain layer.

For me, it makes perfect sense to locate your factories here.

Unsettle answered 10/12, 2012 at 16:25 Comment(0)
J
8

+1 for doing that. Accessibility would be a good reason, I would keep the creational code at least close to the domain model layer. Otherwise users of the domain model will get simply confused how to instantiate it specially when finding restricted access constructors. Actually one sound reason to separate it would be that you have different valid ways to create the same thing e.g. which is the case usually when employing the Abstract Factory.

If I had to separate it I would put it in e.g. a package (in the case of Java) at least the same level of the domain model and ship it always along with it e.g.

upper
  --> domain
  --> domain_factory
Jubbulpore answered 10/12, 2012 at 16:33 Comment(1)
It would appear most people agree with it being in the domain model. so then where do you recommend your Factories exist in the Domain layer? A separate assembly, folder, namespace?Westberry
M
7

I prefer Factories in the Application Layer.

If you keep the Factories in the Domain Layer, they will not help you when you need complex types as parameters (C# code example):

Application Layer:

//this Factory resides in the Domain Layer and cannot reference anything else outside it
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(
            string name, string code, string streetName,...
            and lots of other parameters...);

//these ones reside in Application Layer, thus can be much more simple and readable:
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(CreatePersonCommand);
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(PersonDTO);



Domain Layer:

public class Person : Entity<Person>
{
    public Address Address {get;private set;}
    public Account Account {get;private set;}
    public Contact Contact {get;private set;}
    public string Name {get;private set;}

    public Person(string name, Address address,Account account, Contact contact)
    {
        //some validations & assigning values...
        this.Address = address;
        //and so on...

    }

}

public class Address:Entity<Address>{
    public string Code {get;private set;}
    public string StreetName {get;private set;}
    public int Number {get;private set;}
    public string Complement {get;private set;}
    public Address(string code, string streetName, int number, string complement?)
    {
        //some validations & assigning values...
        code = code;
    }

}

public class Account:Entity<Account>{
    public int Number {get;private set;}

    public Account(int number)
    {
        //some validations & assigning values...
        this.Number = number;
    }

}

//yout get the idea:
//public class Contact...

Also, there is no obligation on keeping Factories inside the Domain Layer (from Domain Driven Design Quickly):

Therefore, shift the responsibility for creating instances of complex objects and Aggregates to a separate object, which may itself have no responsibility in the domain model but is still part of the domain design. Provide an interface that encapsulates all complex assembly and that does not require the client to reference the concrete classes of the objects being instantiated. Create entire Aggregates as a unit, enforcing their invariants.

As I don't use Factories to load persisted objects into memory, they don't have to be accessible from other layers than Application's. Here's why (from Domain Driven Design Quickly):

Another observation is that Factories need to create new objects from scratch, or they are required to reconstitute objects which previously existed, but have been probably persisted to a database. Bringing Entities back into memory from their resting place in a database involves a completely different process than creating a new one. One obvious difference is that the new object does not need a new identity. The object already has one. Violations of the invariants are treated differently. When a new object is created from scratch, any violation of invariants ends up in an exception. We can’t do that with objects recreated from a database. The objects need to be repaired somehow, so they can be functional, otherwise there is data loss.

Munster answered 21/9, 2015 at 15:21 Comment(0)
E
2

CAREFUL with placing 'implementation' in the Domain Layer.

Your domain code doesn't have dependencies. So, you are in trouble if you need to have complex factories.

For example:


// DOMAIN LAYER
public interface IAggregateFactory<TAgg, in TInput>
{
    Task<TAgg> CreateAsync(TInput input);
}

public class AvailabilityFactoryParameters
{
    public string SomeInputParameter { get; set; }
    public string ZipCode { get; set; }
}


// INFRASTRUCTURE/APPLICATION LAYER
public class AvailabilityFactory : IAggregateFactory<GamePredictorAggregate,
    GamePredictorFactoryParameters>
{
    private readonly HttpClient _httpClient;

    public AvailabilityFactory(IHttpClientFactory factory)
    {
        _httpClient = factory.CreateClient("weatherApi");
    }
    public async Task<GamePredictorAggregate> CreateAsync(GamePredictorFactoryParameters input)
    {
        var weather = await _httpClient.GetFromJsonAsync<WeatherDto>($"/weather/{input.ZipCode}");
        return new GamePredictorAggregate(weather.CurrentTemperature, input.SomeInputParameter);
    }
}

public class WeatherDto
{
    public double CurrentTemperature { get; set; }
}

As you can see, now you have a myriad of objects and dependencies available to enrich your factory experience.

So, when you use it in your Application Service, it is easy...

public class GamePredictionService : ApplicationService
{
    private readonly IAggregateFactory<GamePredictorAggregate, GamePredictorFactoryParameters> _factory;

    public GamePredictionService(IAggregateFactory<GamePredictorAggregate, GamePredictorFactoryParameters> factory)
    {
        _factory = factory;
    }
    public async Task CreateNewPredictor(string zipCode, int someOtherParamater)
    {
        var input = new GamePredictorFactoryParameters();
        input.ZipCode = zipCode;
        input.SomeInputParameter = someOtherParamater;

        var aggregate = await _factory.CreateAsync(input);
        // Do your biz operations
        // Persist using repository
    }
}

Now your application service doesn't need to worry about the internals, and your domain objects need to understand how the factory gives them 'birth.'

Summary: Having your implementation in the Domain layer makes only sense if your factory only needs primitive types and nothing else. In cases where you may need to gather data from external services or other application services' DTOs, you want to move the implementation outside. The only 'drawback' is that you need to 'inject' the factory into your application service, but that's not a big deal.

I hope this answer helps to clarify 'where to place Factories.'

Etty answered 20/10, 2022 at 21:13 Comment(0)
C
0

If builders/factories only have dependencies on domain classes and primitives, place them in the domain layer, otherwise place them outside the domain layer.

Circlet answered 6/2, 2014 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.