Avoid Dependency Injection
At least, avoid it when building DDD Aggregates:
Dependency injection of a Repository or a Domain Service into an Aggregate should generally be viewed as harmful. The motivation may be to look up a dependent object instance from inside the Aggregate. The dependent object could be another Aggregate, or a number of them. … Preferably, dependent objects are looked up before an Aggregate command method is invoked, and passed into it.
… Take great care not to add unnecessary overhead that could be easily avoided by using other design principles, such as looking up dependencies before an Aggregate command method is invoked, and passing them into it.
This is only meant to warn against injecting Repositories and Domain Services into Aggregate instances. Of course, dependency injection is still quite suitable for many other design situations. For example, it could be quite useful to inject Repository and Domain Service references into Application Services.
— “Implementing Domain Driven Design”, Vaughn Vernon, p 387.
On a related note, regarding where Entity validation logic goes, we have this …
Validation is a separate concern and should be the responsibility of a validation class, not a domain object.
— ibid., p 208
… and this …
Embedding validation logic inside an Entity give it too many responsibilities. It already has the responsibility to address domain behavior as it maintains its state.
— ibid., p 212
… but then we see this:
How do clients ensure that Entity validation occurs? And where does validation processing begin? One way places a
validate()
method on all Entities that require validation. … Any Entity can safely have itsvalidate()
method invoked. …However, should Entities actually validate themselves? Having its own
validate()
method doesn’t mean the Entity itself performs validation. Yet, it does allow the Entity to determine what validates it, relieving clients from that concern:public class Warble extends Entity { ... @Override public void Validate(ValidationNotificationHandler aHandler) { (new WarbleValidator(this, aHandler)).validate(); } }
… The Entity needs to know nothing about how it is validated, only that it can be validated. The separate
Validator
subclass also allows the validation process to change at a diferent pace from the Entity and enables complex validations to be thoroughly tested.— ibid., p 214-215
It seems like a small step after that to inject a fully-constructed validation object into the Entity at construction time, and have the validate()
method call that, instead of creating a new validation object inside the Entity.