How to work with inheritance on DDD

2019-03-26 16:57发布

问题:

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.

  1. 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?

  2. Or should I not be using inheritance? Why?

  3. 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?

回答1:

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)

EDIT after comments:

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:

  • Favor composition over inheritance (again, I know)
  • You can have a reference from inside an aggregate to the outer world, you shouldn't have a reference the other way around though.