0

Please see the code below:

public IEnumerable<DenominationNumberRequired> CalculateDenominationsFor(int cost) 
    {
        var target = cost;
        foreach (var denomination in currency.AvailableDenominations.OrderByDescending(a => a))
        {
           var numberRequired = target / denomination;
           if (numberRequired > 0)
           {
               yield return new DenominationNumberRequired(denomination, numberRequired);
           }
           target = target - (numberRequired * denomination); 
        }
    } 

Notice that this domain object is responsible for creating DenominationNumberRequired object(s) even though it is not a factory. Should I be injecting a factory into this entity to create the DenominationNumberRequired object(s)? This seems to suggest that I should not: https://stackoverflow.com/questions/20035810/should-domain-objects-have-dependencies-injected-into-them. However, likewise; a domain object that creates other domain objects does not seem right either due to the single responsibility principle.

14
  • Why don't you just have an orchestrator eg.: an application/domain service that does this job, and only pass in value objects, primitives to your entity methods? So you won't have such coupling.
    – kayess
    Dec 14 '17 at 14:17
  • @kayess, because I believe that would make the domain model anemic.
    – w0051977
    Dec 14 '17 at 14:21
  • Not at all, since you have these services for 1. orchestrating, 2. place for logic that does not fit an entity/AR. The rest of the behavior is still locked in/pushed down into your entity.
    – kayess
    Dec 14 '17 at 14:23
  • I don't see the value of a factory here. However I thinkg that the parameter value should very likely not computed here, but computed in the Offer constructor passing the valueCalculator (this assume that this interface is really needed, like having multiple implementation for different cases). Factory are not used just to remove the "new" keyword, they're used to abstract more complex construction involving : a complex object, multiple objects related to each other, specific logic that can eventually depends on configuration files, ...
    – Walfrat
    Dec 14 '17 at 14:23
  • If I got it right, it looks like you have two entities that could be aggregate roots: Member and Offer. What about if Offer is created first in some application service, that this service publishes an event "Offer created", and the other application service assigns it to a member, so that Member is not coupled to Offer object itself, but only to its id? I believe it would look way cleaner. Dec 14 '17 at 14:35
0

Should I be injecting a factory into this entity to create the Offer object?

Short answer: Probably not.

The factory can be a good idea without injecting it into the Member entity.

For example, you can pass it in as an argument to the method

public IEnumerable<DenominationNumberRequired> CalculateDenominationsFor(int cost, Factory<DenominationNumberRequired> factory) 
    {
        var target = cost;
        foreach (var denomination in currency.AvailableDenominations.OrderByDescending(a => a))
        {
           var numberRequired = target / denomination;
           if (numberRequired > 0)
           {
               yield return factory.create(denomination, numberRequired);
           }
           target = target - (numberRequired * denomination); 
        }
    } 

This might be an advantage if you want additional flexibility in the types of your denominations; in your example, CalculatedDenominationsFor doesn't actually care about the type at all, so you might instead write....

public IEnumerable<T> CalculateDenominationsFor(int cost, Factory<T> factory) 

In a case where you actually have constraints on the type (because you need access to methods in the interface), then you might make the signature more specific

public IEnumerable<T> CalculateDenominationsFor(int cost, Factory<T> factory) where T : DenominationNumberRequired

(Disclaimer: JVM programmer trying to guess at C# spellings).

Are you saying that the factory instance should be created in the application service and passed to the domain layer?

You could do that - as far as the application is concerned, the factory is just an opaque handle that it is supposed to pass when the time comes. And yes, in doing that, you end up passing the handle through a lot of locations that don't care very much about it.

That might be a hint that your boundaries aren't in the right places, or that you aren't using the right abstractions as your arguments.

1
  • Thanks for the edit. Are you saying that the factory instance should be created in the application service and passed to the domain layer? This would mean I would have to pass from the application service to domain entity 1 and then from domain entity 1 to domain entity 2.
    – w0051977
    Dec 14 '17 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.