1

Please see the code here and specifically

using System.Collections.Generic; 

 namespace DddInPractice.Logic.Common 
 { 
     public abstract class AggregateRoot
     { 
         private readonly List<IDomainEvent> _domainEvents = new List<IDomainEvent>(); 
         public virtual IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents; 


         protected virtual void AddDomainEvent(IDomainEvent newEvent) 
         { 
             _domainEvents.Add(newEvent); 
         } 


         public virtual void ClearEvents() 
         { 
             _domainEvents.Clear(); 
         } 
     } 
 } 

I am debating whether to use this class in my project. I like the idea because it encapsulates Domain Events. If I use it then all Aggregate Root classes will derive from it. Alternatively, I could use a marker interface like this (which all Aggregate Roots will implement):

public interface IAggregateRoot
{
}

Should I:

  1. Create the base class or

  2. Create the interface or

  3. Do neither?

I like the idea of marking my Aggregate Roots.

  • 4
    What purpose would the interface IAggregateRoot serve here? – David Arno Feb 1 '18 at 12:43
  • 4
    Possible duplicate of: "Should I eat an apple, a banana, or neither?" ;-) – guillaume31 Feb 1 '18 at 12:52
  • 1
    Also, are you not offering us a false trichotomy here? What about 4) Create both? public abstract class AggregateRoot : IAggregateRoot { ... – David Arno Feb 1 '18 at 13:10
  • @David Arno, IAggregateRoot is just a marker interface. – w0051977 Feb 1 '18 at 13:44
  • @w0051977 It does not encapsulate domain events, it just contains them, there is a difference. "Contains" means it just has it inside it, while "Encapsulate" means it "contains" it and does not make it available. – Robert Bräutigam Jul 12 at 12:47
3

AggregateRoot, like Entity and Value, is not (usually) part of the ubiquitous language of your domain. It's really metadata, useful because it allows you to express domain knowledge in an domain agnostic way, so that your generic plumbing can do something useful with it.

As marker interface... well, to be honest, I don't see a lot of value add there.

As a role interface, it communicates the methods that must be implemented to act in the role. This, as noted above, can make it easier to re-use plumbing code.

interface AggregateRoot {
    IReadOnlyList<IDomainEvent> changes();
    void clear();
}

And so you might have, for example

class HibernateCargo implements Cargo, AggregateRoot {
    // ...
}

You can use a base class here, but I find it's better to separate the contract from the implementation.

abstract class AggregateBase implements AggregateRoot {
    // ... 
}

class HibernateCargo extends AggregateBase, implements Cargo {
    // ...
}

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.