Design pattern – Observer

What is it?

Real world

  • Social media
    • When a person updates his status – all his followers gets the notification
    • A follower can follow or unfollow another person at any point of time
    • Once unfollowed, person will not get the notifications from subject in future

Real world diagram

  • One-to-many dependencies between objects
  • Also known as publish-subscribe pattern
  • There are many observers (subscriber objects) that are observing a particular subject (publisher object)
  • Observers register themselves to a subject to get a notification when there is a change made inside that subject

Sequence diagram

Architecture

Coding example

Subject and concreteSubject

  • Subject – interface or abstract class defining the operations for attaching and de-attaching observers to the subject
  • ConcreteSubject – concrete Subject class. It maintain the state of the object and when a change in the state occurs it notifies the attached Observers
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Subject
public interface Subject
{
public void attach(Observer o);
public void detach(Observer o);
public void notifyUpdate(Message m);
}
// Subject public interface Subject { public void attach(Observer o); public void detach(Observer o); public void notifyUpdate(Message m); }
// Subject
public interface Subject
{
    public void attach(Observer o);
    public void detach(Observer o);
    public void notifyUpdate(Message m);
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// MessagePublisher.java
import java.util.ArrayList;
import java.util.List;
public class MessagePublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer o) {
observers.add(o);
}
@Override
public void detach(Observer o) {
observers.remove(o);
}
@Override
public void notifyUpdate(Message m) {
for(Observer o: observers) {
o.update(m);
}
}
}
// MessagePublisher.java import java.util.ArrayList; import java.util.List; public class MessagePublisher implements Subject { private List<Observer> observers = new ArrayList<>(); @Override public void attach(Observer o) { observers.add(o); } @Override public void detach(Observer o) { observers.remove(o); } @Override public void notifyUpdate(Message m) { for(Observer o: observers) { o.update(m); } } }
// MessagePublisher.java
import java.util.ArrayList;
import java.util.List;
 
public class MessagePublisher implements Subject {
     
    private List<Observer> observers = new ArrayList<>();
 
    @Override
    public void attach(Observer o) {
        observers.add(o);
    }
 
    @Override
    public void detach(Observer o) {
        observers.remove(o);
    }
 
    @Override
    public void notifyUpdate(Message m) {
        for(Observer o: observers) {
            o.update(m);
        }
    }
}

Observer and ConcreteObservers

  • Observer – interface or abstract class defining the operations to be used to notify this object
  • ConcreteObserver – concrete Observer implementations
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Observer.java
public interface Observer
{
public void update(Message m);
}
// Observer.java public interface Observer { public void update(Message m); }
// Observer.java
public interface Observer
{
    public void update(Message m);
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// MessageSubscriberOne.java
public class MessageSubscriberOne implements Observer
{
@Override
public void update(Message m) {
System.out.println("MessageSubscriberOne :: " + m.getMessageContent());
}
}
// MessageSubscriberTwo.java
public class MessageSubscriberTwo implements Observer
{
@Override
public void update(Message m) {
System.out.println("MessageSubscriberTwo :: " + m.getMessageContent());
}
}
// MessageSubscriberThree.java
public class MessageSubscriberThree implements Observer
{
@Override
public void update(Message m) {
System.out.println("MessageSubscriberThree :: " + m.getMessageContent());
}
}
// MessageSubscriberOne.java public class MessageSubscriberOne implements Observer { @Override public void update(Message m) { System.out.println("MessageSubscriberOne :: " + m.getMessageContent()); } } // MessageSubscriberTwo.java public class MessageSubscriberTwo implements Observer { @Override public void update(Message m) { System.out.println("MessageSubscriberTwo :: " + m.getMessageContent()); } } // MessageSubscriberThree.java public class MessageSubscriberThree implements Observer { @Override public void update(Message m) { System.out.println("MessageSubscriberThree :: " + m.getMessageContent()); } }
// MessageSubscriberOne.java
public class MessageSubscriberOne implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberOne :: " + m.getMessageContent());
    }
}

// MessageSubscriberTwo.java
public class MessageSubscriberTwo implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberTwo :: " + m.getMessageContent());
    }
}

// MessageSubscriberThree.java
public class MessageSubscriberThree implements Observer
{
    @Override
    public void update(Message m) {
        System.out.println("MessageSubscriberThree :: " + m.getMessageContent());
    }
}

State object

This must be an immutable object so that no class can modify it’s content by mistake

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Message.java
public class Message
{
final String messageContent;
public Message (String m) {
this.messageContent = m;
}
public String getMessageContent() {
return messageContent;
}
}
// Message.java public class Message { final String messageContent; public Message (String m) { this.messageContent = m; } public String getMessageContent() { return messageContent; } }
// Message.java
public class Message
{
    final String messageContent;
     
    public Message (String m) {
        this.messageContent = m;
    }
 
    public String getMessageContent() {
        return messageContent;
    }
}

Test communication between publisher and subscribers

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Main.java
public class Main
{
public static void main(String[] args)
{
MessageSubscriberOne s1 = new MessageSubscriberOne();
MessageSubscriberTwo s2 = new MessageSubscriberTwo();
MessageSubscriberThree s3 = new MessageSubscriberThree();
MessagePublisher p = new MessagePublisher();
p.attach(s1);
p.attach(s2);
p.notifyUpdate(new Message("First Message")); //s1 and s2 will receive the update
p.detach(s1);
p.attach(s3);
p.notifyUpdate(new Message("Second Message")); //s2 and s3 will receive the update
}
}
// Main.java public class Main { public static void main(String[] args) { MessageSubscriberOne s1 = new MessageSubscriberOne(); MessageSubscriberTwo s2 = new MessageSubscriberTwo(); MessageSubscriberThree s3 = new MessageSubscriberThree(); MessagePublisher p = new MessagePublisher(); p.attach(s1); p.attach(s2); p.notifyUpdate(new Message("First Message")); //s1 and s2 will receive the update p.detach(s1); p.attach(s3); p.notifyUpdate(new Message("Second Message")); //s2 and s3 will receive the update } }
// Main.java
public class Main
{
    public static void main(String[] args)
    {
        MessageSubscriberOne s1 = new MessageSubscriberOne();
        MessageSubscriberTwo s2 = new MessageSubscriberTwo();
        MessageSubscriberThree s3 = new MessageSubscriberThree();
         
        MessagePublisher p = new MessagePublisher();
         
        p.attach(s1);
        p.attach(s2);
         
        p.notifyUpdate(new Message("First Message"));   //s1 and s2 will receive the update
         
        p.detach(s1);
        p.attach(s3);
         
        p.notifyUpdate(new Message("Second Message")); //s2 and s3 will receive the update
    }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Console output
MessageSubscriberOne :: First Message
MessageSubscriberTwo :: First Message
MessageSubscriberTwo :: Second Message
MessageSubscriberThree :: Second Message
// Console output MessageSubscriberOne :: First Message MessageSubscriberTwo :: First Message MessageSubscriberTwo :: Second Message MessageSubscriberThree :: Second Message
// Console output
MessageSubscriberOne :: First Message
MessageSubscriberTwo :: First Message
 
MessageSubscriberTwo :: Second Message
MessageSubscriberThree :: Second Message

Be the first to comment

Leave a Reply

Your email address will not be published.


*