I am currently trying out DDD and reading Evans book. I have arrived at a model that has an aggregate whose root is Student
. Now I need to have (or be able to distinguish) a RegisteredStudent
and an EnrolledStudent
(inherits RegisteredStudent
). I don't know how to handle inheritance in DDD.
Should the 2 inherited classes be inside the aggregate? If so, are they also considered aggregate roots since their identity is the same as the root (there are only added properties to them)? If not, how do I give access to them from other entities?
Or should I not be using inheritance? Why?
And also, what if you have an entity in an aggregate that isn't a root, but you need it to inherit an entity outside? How should you go about it?
However, it is also possible to use inheritance when defining a database model. When we create the logical model, we can apply the concept of inheritance to represent the idea that an entity (often called the child entity) is derived (i.e. it inherits) from another entity (the parent entity).
When we create the logical model, we can apply the concept of inheritance to represent the idea that an entity (often called the child entity) is derived (i.e. it inherits) from another entity (the parent entity). Usually, the child entity has all the elements of its parent entity, plus some additional attributes.
Note that the table vehicle has columns taken from four different entities in the inheritance model: vehicle, car, bike, and electrical_bike. Many columns are nullable; in this table we can represent car objects or bike objects; thus, if a record is representing a car, all bike related attributes will be NULL.
In other words, all the attributes from any entity in the inheritance will be in the generated table. It is important to note that the generated inheritance table will have an additional column called discriminator, which will be used to identify what type of entity in the hierarchy the record is representing.
What you need to ask yourself here is whether a RegisteredStudent
and an EnrolledStudent
are different concepts. Are they not both students, but just in a different state?
In general, you should favor composition over inheritance.
Here's an example of what I would do. (Note that it's just my example, I don't know the domain, so it's not a definitive solution).
You could have a Student
class, which is your aggregate root and then a few different state classes: Registered
and Enrolled
. That way you don't need to expose these state classes on the student but you could just expose methods on the Student. A small example in C#:
class Student
{
State _currentState;
void Enroll()
{
if(!_currentState is Registered)
throw new InvalidOperationException("Cannot enroll student who is not registered");
this._currentState = new Enrolled();
}
void Register(string name)
{
this._currentState = new Registered(name);
}
}
class StudentState{}
class Enrolled : StudentState
{}
class Registered : StudentState
{
public Registered(string name)
{
Name = name;
}
public string Name {get; private set;}
}
This is a simple application of the State design pattern, you could externalize more parts of it and build a complete state-machine, but I'll leave that up to you. (Also it's typed directly in to the SO-editor, so there could be syntax errors)
Whether you need to expose a State-property or not depends on the context. In general I would recommend not to do that, because you're exposing the internals of the Student
. It would be better to expose a method called CanEnroll
for example. That way you can change the internal implementation of your state pattern without affecting any clients.
As for question 3, it's hard to say without a use case. However, here are some guidelines:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With