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.
- Main Class calls the
register()
method of AlertService
class. - Main Class starts the packet acceptor thread.
- Project Acceptor accepts new car and starts
PacketAnalyzer
. PacketAnalyzer
reads data from the socket and parses the accepted packet. - It then starts
PacketProcessor
that detect the changes in packet and call the Observers.
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.
public interface IPacketChange {
public void notifyAlert(PacketV3 packet);
}
In the AlertService
class, we anonymously implement the interface
and add into the corresponding list.
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 ArrayList
s 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.
if(packet.getEngineStatus() != previousPacket.getEngineStatus()){
for(IPacketChange iPacketChange : onEngineStatusChange){
iPacketChange.notifyAlert(packet);
}
}
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.
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.