News Ticker

Observer Pattern

Observer Pattern

A little bit difficult to understand why it is needed in the first place and it goes down to the basic fundamental requirement of OO systems which is to pass a message from one object to another telling the object to do something as a result of a state change on another object but the big difference here verse simply invoking a method on a dependent object is that you care about decoupling in one way or another. Perhaps you have an event for which you want to trigger observers, multiple observers, multiple endpoints that react to that particular endpoint because you want some loose coupling because you want to change which observer actually gets triggered at runtime. This is the original reason you need the observer pattern.

The way you implement the observer pattern is sort of antithetical to the original goal of the observer, the GoF way is to implement the interface on a bunch of objects, then on the listener, you have to register the concrete implementations of each of those instances.  It’s a bit self-defeating if the goal is to create loosely coupled systems.

How does Java EE solve this, it does it in a much more loosely coupled fashion.

@Stateless
public class PublishService {

  @Inject
  Event<String> event;

  public void producer() {
    event.fire("Take me to your leader");
  }

}

Event

In this code snippet, we have a stateless bean that is listening for events of type String. When it hears such an event it calls event.fire and gives it the payload that the observer is expecting. In this case, it is a welcome message. All dependents are notified.

@Stateless
public class MessageObserver {

  public void trace(@Observes String message) {
    System.out.println(message);
  }

}

The observer has a method with its expected payload which is marked with the Observe annotation, this says: observe for any events that match the payload type of the parameter, in this case, a String.

You can also use qualifiers here to filter events. You can qualify the Observes annotation by using the @Named annotation or a custom qualifier, when you fire it you can statically provide the qualifier at the event injection point and also in the observer method parameter.

@WarningMessage
@Inject
Event<String> event;

public void trace(@Observes @WarningMessage String message){}

By default they are synchronous, however, in CDI 2.2 they are introducing asynchronous processing of events.

Use case

Imagine that you have significant events in your application that you need multiple endpoints to react upon and they are not important enough to put in messaging middle-ware perhaps a system warning: this light-weight approach is perfect for that situation.

You might be thinking: How about transactions? Events don’t have much to do with transactions, the only place that they interact is that you can have an observer that listens on the transaction so you can get call backs saying that the transaction got committed or rolled back.

The Good, Bad and the Ugly

The Good

It is very easy to implement with no boilerplate code. It can be used as light weight messaging system that is less than JMS as the container does the heavy lifting.

The Bad

The execution order is confusing but IDE will help.

The Ugly

Nothing, it’s beautiful.

What Next?

Java EE has simplified many other patterns such as the Singleton PatternDecorator PatternFacade Pattern and Factory Pattern.

Leave a Reply

%d bloggers like this: