-2
class DomainEvent {

}

and then I have different events with following structure:

class SomeEvent extend DomainEvent {
   private UUID orderId;
   private UUID orderlineId;
   private UUID productId;
}

Now lets say that I have 20 such events and most of them have orderId + orderLineID as attributes som have in addition productID.

There are also some events that are not oriented around the Order , so they may have differnt fields.

In the begining I though mayve I can create

abstract AbstractOrderEvent extends DomainEvent {
   private UUIID orderId;
}

and then

abstract AbstractOrderLineEvent extends AbstractOrderEvent {
   private UUID orderlineId;
}

and then

abstract AbstractProductEvent extends AbstractOrderLineEvent {}

But it looks to me plain ugly! Maybe my own taste.

Then I thought maybe I can do the same with interfaces. But to be honest it does not look much better.

I also thought to have something like

DomainEvent<T extends Subject> {
T  subject ( and then the subject to has different attributes)

}

and then I can have something like

OrderCompleytedEvent extends DomainEvent {

}

How can I model this case ?

Pesho
  • 540

2 Answers2

1

There are three different sets of relationships to represent here:

  • The relationships among the domain entities. If an "Order Line" is always part of a specific "Order", you should represent that directly, not by always passing them as a pair. Similarly, if an "Order Line" has a specific "Product" attached to it, you shouldn't need to pass that Product around specifically, it's a dependent field of the Order Line. Most of these relationships will be composition, not inheritance. This should be your primary focus, since it will affect all areas of the application, not just the event system.
  • The relationships among the events. For instance, you might have a service that's interested in all events that affect product inventory, and another service that's interested in all events that involve payments. Those categories of events might expose similar behaviours, e.g. getting the total amount of money transacted. That might well be a directed graph rather than a tree, so depending on the language you're using could be modelled with multiple inheritance, interfaces, traits, etc.
  • The relationships between the two sets of objects. Your events are currently very thin, holding only UUIDs; this might be a reasonable way to store and transmit them, but your customers aren't buying UUIDs, they're buying products, so that's what your application should be modelling. An "Order Line Created Event" could contain a single "Order Line" object, from which all its details can be obtained. An "Order Line Updated" event could contain separate "before" and "after" Order Line objects.
IMSoP
  • 5,947
1

IMSoP is correct in identifying that abstraction without a purpose is meaningless, so we need to know what you intend to achieve. To quote an answer I wrote in the past on the same topic, abstraction without a concrete goal is turtles all the way down.

Your response:

Yes reduce Copy paste mostly. Same methods being pasted around again and again. A good abstraction can eliminate this.

The main issue here is that just because two things are structurally the same, does not mean that they (or their similarities) are actually the same thing.

Reducing copy/paste by creating shared logic is only applicable when the duplicate instances share the same lifecycle, i.e. changing one inherently means changing the other.

While you may have several events that happen to have some similar properties; do those events share an actual life cycle? My guess is not, since events tend to be independently defined.
This principle extends beyond events, well into general OOP. Classes exist because they have a responsibility, and as clean code dictates each class should have only one responsibility. Two responsibilities therefore need to be represented by two classes.

This remains correct even if these classes happen to be structurally equal to one another.

A simple example here is a domain object, data entity and (public) DTO. These three classes could all have the exact same set of properties, but they each have their own unique purpose, and they should therefore not be lumped into a single class.

When trying to refactor code, you have to distinguish coincidence from correlation. If you spot a similarity, and there is a correlation here (e.g. if one changes, the other must change too), then there's reason to abstract. But if it is coincidence, i.e. they are completely unrelated except that they happen to look the same for different reasons, then abstraction would actually be introducing problems instead of solving them.

So I'd advise against trying to merge these events into some shared logic just because they happen to be structurally similar at the moment.

Flater
  • 58,824