7

(Note: I'm not sure how to frame the question properly, so please feel free to edit it or comment about how I can improve it.)

I guess this question, while covering a fairly wide scope, is pretty limited to statically typed (object-oriented) languages (I'm using Java in particular) for implementing CQRS and Event Sourcing. I've designed events pertaining to one particular aggregate as a hierarchy, in that they are subclasses of one parent class. Say I have an Order aggregate, and I have an OrderEvent base class whose subtypes are specific events like OrderPlaced, QuantityUpdated, OrderCancelled, etc.

Now, inside this Order aggregate, I have overloaded apply methods that take specific subtypes of OrderEvent, like apply(OrderCancelled), and apply(QuantityUpdated). However, when reconstituting an Order object from the event source, what I have is a list of objects whose declared interface is just OrderEvent. Although technically, the underlying system keeps track of which specific subtype each of those objects are, there is no way in the code to imply that I've provided apply methods for each type specifically. I have to define a method that takes the parent OrderEvent class: apply(OrderEvent).

Are there existent patterns around this that I'm not aware of? Or is something like the following the only option (written in Java):

void apply(OrderEvent event) {
    if (event instanceof OrderPlaced) {
        apply((OrderPlaced) event);
    }
    if (event instanceof QuantityUpdated) {
        apply((QuantityUpdated) event);
    }
    if (event instanceof OrderCancelled) {
        apply((OrderCancelled) event);
    }
}

I considered defining an applyTo method in the OrderEvent parent class/interface that takes an Order object to which the particular OrderEvent object gets applied to. For example:

class OrderPlaced extends OrderEvent {
    void applyTo(Order order) {
        order.apply(this);
    }
}

This will allow me to define apply(OrderEvent) in Order class as:

void apply(OrderEvent event) {
    event.applyTo(this);
}

It results in a more concise code, but I'm not so sure about the almost circular nature of the approach.

What's the common pattern used for this?

3

This is simply strategy pattern with an additional parameter for the "context" passed to the strategy, like in this SO question. It results in a tight, bidirectional coupling between OrderEvent and Order (which might be fine for this case). If each OrderEvent object is always associated with the same Order object, better pass this (the Order object) as a constructor parameter into the related OrderEvent, you can save the parameter in the applyTo method then (however, the coupling will stay) . If the same OrderEvent can be applied to different orders, your solution is fine.

P.S:: this is in no way special to DDD, CQRS, or event-sourcing, so I think your question tags don't fit well.

  • 1
    Regarding the tags, I chose them because I originally wanted to frame this problem specifically in the context of CQRS and Event Sourcing. I'm aware that it's more of a general object-oriented programming question, but when it's in the context of those patterns, it becomes a little more specific. For example, the question of whether the tight coupling between Order and OrderEvent is acceptable, I think, may be assumed through the context. I also wanted to learn about how people with experience on implementing them have done similar things in the past. – Psycho Punch Jul 3 '17 at 17:36
  • As for constructing OrderEvent by passing an Order object as parameter, I'm not so sure about that. I have designed my OrderEvent objects to refer to related Order objects indirectly through the orderId field. As a general rule, OrderEvents can only be applied to a single Order. However, that is not reflected directly through language/system construct, as some sort of design trade-off. – Psycho Punch Jul 3 '17 at 17:58
3

Unfortunately Java does not support multiple dispatch but you can use reflection to call the appropriate method without breaking the Open close principle or introduce accidental dependency between events and aggregates.

So, you could use a dispatcher that identify the right apply method and then call it:

class Dispatcher {
   public void applyEvent(Object aggregate, Object event) {
      Method m = aggregate.getClass().getDeclaredMethod('apply',new Class[](event.getClass());
      m.invoke(aggregate,new Object[](event);
   }
}

How do you use this component is up to you (for example you could adapt it to be a base class that Aggregate roots inherit from it).

  • 1
    Thanks. Java may not have support for multiple dispatch, but your answer actually lead me to the visitor pattern, which is, in this case, like a work-around pattern. The approach I considered looks like it's actually the visitor pattern. – Psycho Punch Jul 4 '17 at 12:33
  • @PsychoPunch Intentionally I've put the link to "multiple dispatch" in order to guide you to other sources. However, have you tried my actual answer? – Constantin Galbenu Jul 4 '17 at 12:39
  • I didn't really try your suggestion. Just like Java's instanceof operator, I'd rather not use reflection as much as possible. I can see how it might work (with some modifications) though. – Psycho Punch Jul 4 '17 at 12:55
  • @PsychoPunch I've asked because the visitor pattern seems like an overkill, you'll have to create a lot of visitor classes. – Constantin Galbenu Jul 4 '17 at 12:59
  • Oh, actually it fits my code base rather well. I already have a hierarchy of OrderEvent classes, which act as the Visitable components. The Order, by defining an apply method for each OrderEvent subtype, is already a suitable Visitor component. It's really a good fit. – Psycho Punch Jul 4 '17 at 13:13
2

Excuse me if I understand incorrectly the context of your need here but what I understand is that you need to apply a different implementation to each event based on what sub-class it was constructed from. In general, whenever I have to resort to instance of and overloading the apply method for instance for each sub-class makes me go back to the design board because it means I ve done something wrongly.

In my opinion you should make the generic method signatures(like apply,do,get,set etc) that all your delegate order event objects should have, an interface or a super class with said methods as abstracts(to force the subclasses to implement them). Then you implement this in every OrderEvent subclass to differentiate the behavior the way you need. Then its a matter of of your single apply methods having an Interface or super Class object as argument and then simply calling the appropriate generic method from within the apply method, the compiler will know at runtime what type of object you have and call the appropriate method for it then.

To visualize this a bit better consider this:

interface OrderEvent{
(abstract)do();get();set();
}
class OrderCancelled implements or extends OrderEvent{
do(){ logic;} get(){logic;} set(){logic;}
}
class CompositeOrderWithDelegate(){
 apply(OrderEvent oe){
  oe.do();
 ...
 }
}
0

You second approach is good, although right now this will lead to a cycle. What you have to do is put the real event logic into the event.

Now you do

class OrderPlaced extends OrderEvent {
    void applyTo(Order order) {
        order.apply(this);
    }
}

What you should do imo

class OrderPlaced extends OrderEvent {
    void applyTo(Order order) {
        //real logic what happens in order class happens here now
        order.setDate(date);
        order.doThis(var1);
        order.doThat(var2);
    }
}

So only your OrderEvents know how they are applied to the Order and your Order class doesn't know a thing. Now you can create as many OrderEvent subclasses as you like without touching the Order class ever again.

  • I'm not really sure I agree with your suggestion. The circular apply and applyTo calls to me smelled of tight coupling, which is in most cases a bad thing. What you're suggesting somehow looks like feature envy to me, although I'm not so sure about that. I would really rather the Order object manage its own state transition instead of exposing generic mutators. – Psycho Punch Jul 3 '17 at 17:50
0

What's the common pattern used for this?

You've really discovered both of the main patterns used.

It results in a more concise code, but I'm not so sure about the almost circular nature of the approach.

Yes, that's a code smell.

In short, you've made a decision that these events all extend a common root -- which is fine. But you've then let that decision about the events leak into the Order. That's not so good.

Hiding decisions in modules is an important part of making changes to code easy. You want to be minimizing the number of places that are intimate with a decision so that you are free to change it later.

The design below is analogous to what you are doing now

class API {
    interface OrderEvent {
        void applyTo(Order order);
    }
    interface OrderPlaced extends OrderEvent {
        // ...
    }
}
class Data {
    class OrderPlaced implements API.OrderPlaced {
        public void applyTo(Order order) {

        }
    }
}

But it tangles your concerns; anybody that needs to know about OrderPlaced also needs to know about applyTo, which makes no sense since they are never going to use that information for anything.

Compare with:

class API {
    interface OrderPlaced {
        // ...
    }
}
class History {
    interface OrderEvent {
        void applyTo(Order order);
    }
}
class Data {
    class OrderPlaced implements API.OrderPlaced, History.OrderEvent {
        public void applyTo(Order order) {

        }
    }
}

The code that knows about heterogeneous collections of order events needs the History.OrderEvent interface, but doesn't need to know anything about OrderPlaced or the implementation details. Order needs to know about API.OrderPlaced, but nothing about the fact that orders are generic.

Anything directly coupled to the implementation (the class itself, the factory that invokes its constructor) of course needs to know the whole truth.

  • The thing is, in the context of Event Sourcing, I will need the Order to also be aware of the more generalized OrderEvent class. To reconstitute an Order object based on a chronologically events, I would need a generic OrderEvent list whose elements I would do not readily know the specific type of. All I know is that I have a collection of OrderEvent objects, and that I have to apply them into the Order object one by one based on their timestamp. – Psycho Punch Jul 5 '17 at 14:10

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.