Juan Vega
Juan Vega

Reputation: 1120

how to implement state pattern using ddd

I have a question about the state pattern and how to implement it using DDD. For what I understand of the state pattern, the pattern is used to handle the transition between different states, so its the responsibility of each state to handle what the system has to do to transit to the new state. To do so, using polymorphism, each state can be a class of its own that extends one base class, implementing the transitions from one state to the other, following a graph that defines the possible transitions.

I've been looking for information on how to do this using DDD and, among other web sites, I found this one that uses enums.

http://nurkiewicz.blogspot.co.uk/2009/09/state-pattern-introducing-domain-driven.html

The reason for using enums is that you can persist the current state, in this case the name of the enum, to a repository, so your aggregate can be recreated later. So, following the state pattern definition, the state can receive different parameters (for example, the new value of a field) so the context (in this case the aggregate) can transit to the new state and update its fields so the state is consistent. This means, the state would be the one responsible to update the values of the aggregate.

My question is, is this the right thing to do? For what I understand, in DDD the aggregate is the one that knows about its internals and, whenever an entity inside the aggregate has to be changed, the aggregate has to expose a method which later on would call the entity to change its value. This way the entities are encapsulated inside the aggregate and they cannot be accessed directly from outside it.

But using this implementation of the state pattern it's the entity (or value object, I don't know how to call the state) who changes the aggregate. You can even use the enum directly and call an operation inside it passing your aggregate and the aggregate would be changed.

Another question about this is; the moment you have to provide some behaviour to your aggregate that depends on the current state, where do you do the implementation? Inside the aggregate, adding more operations to the base class of the state to check if the state is one or the other? Or inside the state, so the state uses the aggregate to call the different methods that it exposes to provide that functionality? The first approach would mean that, depending on the number of states you have, you would have create many methods just to check if you are in the correct state for your purposes. The other one would imply that is again the state who coordinates the way the aggregate has to call its internals.

Sorry if this question has being asked before. I've looking for days and I couldn't find something similar to what I'm asking here.

Thanks in advance.

EDIT:

Sorry for the late response, I was on holidays.

In my case the states are rather simple. They would reflect the different states of a tournament (NEW, OPEN_REGISTRATION, CLOSED_REGISTRATION, IN_PROGRESS, FINISHED, CANCELLED). What I'm trying to do is a probe of concept following the approach from the link I provided.

My question here is: the moment the aggregate (context) has to do something that depends on the state (like register a player), where would you hold that logic? Inside the context, checking first if the state class is of type OpenRegistrationState? Or inside the state classes, providing an implementation inside the OpenRegistrationState that stores the player into the context (the method would expect both the context and the player as parameters) and throwing and exception from the other ones?

It seems like using the second approach, the logic inside the context is quite simple, it only has to call the current state to do the job for it. The problem is, the moment you have many different methods that relies on the state to operate, your state classes would have an explosion of different methods that only one or two of them would implement while the other ones would throw an exception. In that case, I don't know if it would be easier to forget about the state pattern and just use an enum and check the value whenever some logic depends on the current state.

Upvotes: 0

Views: 3308

Answers (1)

Fuhrmanator
Fuhrmanator

Reputation: 12912

The state pattern's context says that an object's behavior is dependent on its state, and its methods contain if/then (or case) logic reflecting conditions based on states. The pattern provides an alternative to those case statements.

The solution is to create classes for each state, implementing a common interface. State-dependent operations are delegated from the context object to its current state object. The context object points to a state object that reflects its current state.

So, if I understand your question, then Domain objects (à la DDD) are the context objects and you want to avoid case logic in them. Otherwise, you don't need the state pattern (and you can stop reading now if you want, since the rest doesn't apply).

Craig Larman's Applying UML and Patterns 3rd Edition book has a chapter on Designing a Persistence Framework with Patterns and a section on Transactional States and the State Pattern. I believe his approach is compatible with DDD as it has been defined here. Actually, it's a variant of the PersistentObject idea from Scott Ambler

State Pattern applied for persistent domain object

Domain classes have state. In this example, the states are about persistence: New, OldClean, OldDirty, OldDelete and Deleted. See Larman's book for the details.

A couple of details I couldn't easily annotate on the PlantUML image above:

  • the PObjectState abstract class has default no-op bodies for each method (transition)
  • the implementations, e.g., OldDirtyState.commit(...) handle the implementation of the behavior based on state. For persistence, this makes sense since they are generally behaviors that aren't related to domain logic. A rollback of a persistent object is basically the same.

Larman has a footnote stating "Whenever a domain object class extends a technical services class, it should be pause for reflection, as it mixes architectural concerns (persistence and application logic)."

You didn't use a concrete example of what exactly the State is that you want to model, so I am not sure whether this example applies appropriately.

If your State is some cross-cutting concern that introduces unwanted coupling in your domain objects, then you have to ask yourself the question which is worse: Case logic in the Domain objects, or unwanted coupling. Designs are trade-offs and you have to pick your battles.

Upvotes: 2

Related Questions