Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Observer Design Pattern in Java Multithreaded Application

5.00/5 (2 votes)
25 Jan 2018CPOL4 min read 14.3K   120  
An article on how to implement Observer Design pattern in Mutithreaded Java application when Function pointer is needed

Introduction

From Observer Design Pattern concept, we know that observers register to a subject. Once notification is received from subject, observers call the subject and get data that is changed.

Plus there is a OneToMany relationship between Subject and Observer. But the confusion arises when the subject has multiple parts that can change simultaneously.On that time, the “OneToMany” relation seems like a “ManyToMany” relation that arises confusion in the implementation process.

This article will help you to clear this confusion.

Real Life Scenario

Say we are working on a vehicle tracking system. And this system sends SMS/email to its user when the car starts/stops, when the AC is on/off or when a GPS is lost.

No matter whether the car owner is inside the car or not, he will always get notification when someone else is driving the car (may be the thief ;) ).

Device attached with the car sends a packet to the server, service parses that packet, compares with previous packet and detects engine/AC status changes (On/Off).

Here, packet can change its engine, AC or GPS status separately or all at the same time.

Consider that the user turns on the ac at the very first time and the sky is so clear to get full GPS.

So, all the status bits are 1. When he stops the car, engine and AC status become 0 at the same time. Here, Engine and AC status is 0 but GPS status is still 1.

Where is the Confusion

Registered observers will be notified by this status change scenario but what status actually changed? Have multiple status changed or a single status ?

If multiple status change, multiple observers deal with multiple changes of one packet.

(Engine and AC status change at the same time. Both Email and SMS service have to send two separate emails/SMS for these two status changes).

Enough reasons for a “ManyToMany” mis assumption, that violates Observer Pattern law.

Actually, it’s still a “OneToMany” relationship when you detect the changes separately and run the alert service methods from a single pointer.

Developer has to list up all the AlertService methods into somewhere and when any of the status change, he will loop over that list.

For each change, loop over the list that contains the methods.

Now the question is how? Java does not support function pointer. How to list up the methods into a single place?

Answer: By using Interface

Project Architecture

Every time a new car comes, it will be connected via a new thread.

  1. Main Class calls the register() method of AlertService class.
  2. Main Class starts the packet acceptor thread.
  3. Project Acceptor accepts new car and starts PacketAnalyzer.
  4. PacketAnalyzer reads data from the socket and parses the accepted packet.
  5. It then starts PacketProcessor that detect the changes in packet and call the Observers.

Image 1

All alert services will be registered (actually a List implementation) to our subject, observe changes in packet and fire events (loop over the list) when there is a change in packet.

How to Implement

Let’s explore more with a coding example.

Packet Structure: HardwareId, Latitude, Longitude, Engine_Status, Ac_Status, Gps_Status

Sample packet: 000001, 23.819624, 090.366783, 1, 0, 1

Here,

  • engine status = on
  • ac status = off
  • hasGps = true

Start with the Interface.

Java
public interface IPacketChange {
  public void notifyAlert(PacketV3 packet);
}

In the AlertService class, we anonymously implement the interface and add into the corresponding list.

Java
PacketProcessor.onAcStatusChange.add(new IPacketChange() {
  @Override
  public void notifyAlert(PacketV3 packet) {

    sendSMS(packet,"ac");
    sendEmail(packet,"ac");
  }
});

PacketProcessor.onEngineStatusChange.add(new IPacketChange() {
  @Override
  public void notifyAlert(PacketV3 packet) {

    sendSMS(packet,"engine");
    sendEmail(packet,"engine");
  }
});

Here, onAcStatusChange and onEngineStatusChange are two ArrayLists from PacketProcessor.

Why these two lists are inside PacketProcessor but not in AlertService?

You will get the answer soon.

After service registration, PacketAcceptor and PacketAnalyzer creates socket from serversocket and accepts packets from car.

I am skipping this part as it's normal socket programming, besides you can download the source code here.

If there is any question regarding this part, let me know in the comments section.

After analyzing data by PacketAnalyzer, it starts PacketProcessor. Packet processor compares current packet with previous packet and detects changes separately.

Java
if(packet.getEngineStatus() != previousPacket.getEngineStatus()){
  for(IPacketChange iPacketChange : onEngineStatusChange){
    iPacketChange.notifyAlert(packet);
  }
}
Java
if(packet.getAcStatus() != previousPacket.getAcStatus()){
  for(IPacketChange iPacketChange : onAcStatusChange){
    iPacketChange.notifyAlert(packet);
  }
}

This is how Interface is the life saver here. We need not to worry about the listing/pointer of those sendSMS() and sendEmail() methods.

For each status change, individual alert service will be notified from the corresponding list.

And inside the list, we have anonymous class implementation of the Interface. sendSms() and sendEmail() are calling inside that anonymous class.

Why This Architectural Model Useful

When we are going to introduce a new alert service (this time push notification), we will just create a new method sendPushNotification() inside AlertService and call it from the anonymous class.

Image 2

So, all changes are in a single class, no need to touch any code inside the PacketProcessor or any other service class.

Modularity is the advantage here.

N.B.: I have used multithreading so that each car will communicate by a separate thread and one thread does not affect another thread. Both Sender and Main Project have been uploaded here. Please run the Main Project first then send data using the sender project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)