Observer Design Pattern

By Hikmet Cakir

Observer Design Pattern

Observer is a structural design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.


Sometimes a structure may need to be changed and some structures are need to be notified about changing. Roughly, the change may need to be reported to another place or places.


For instance, let’s suppose we’re a ticket seller. We’re selling concert tickets and customers tell us their own attention areas for example a customer tell to us he likes Jazz, Blues and Country genres etc. and if there are some events related with customer’s own attention areas, the system will notify the customer. For structures like this, we should use observer design pattern.


How to Implement

  1. Declare the subscriber interface. It generally contains only one method which name is update.
  2. Implement the update notification methods in concrete subscriber class.
  3. Create a manager class to manage methods that is related with notification mechanism such as add subscriber, remove subscriber and send notify etc.
  4. Create a concrete publisher class. This class does various operations then it calls creating manager class’s notify method to send notification.
  5. The client must create all necessary subscribers and register them with proper publishers.


Example Implementation

I had given an example about concert ticket seller before. Let’s implement this structure. Firstly, we should declare a subscriber interface so I defined a interface that name is EventListener. This interface contains only one method.


public interface EventListener {
    void update(Genre genre, EventDetail eventDetail);
}

Secondly, the concreate subscriber classes which implements subscriber interface should be defined. I created two concreate subscriber classes which names are SmsNotificationListener and EmailNotificationListener. Both of them implement EventListener class.

public class SmsNotificationListener implements EventListener {


    private String phoneNumber;


    public SmsNotificationListener(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }


    @Override
    public void update(Genre genre, EventDetail eventDetail) {
        System.out.println("Sms to " + phoneNumber + ", Genre: " + genre + ", Event Details: " + eventDetail);
    }
}


public class EmailNotificationListener implements EventListener {
    
    private String email;


    public EmailNotificationListener(String email) {
        this.email = email;
    }


    @Override
    public void update(Genre genre, EventDetail eventDetail) {
        System.out.println("Email to " + email + ", Genre: " + genre + ", Event Details: " + eventDetail);
    }
}

Thirdly, we should define manager class to manage events. Basically, this class should contain some methods that provides event managing such as add subscriber, remove subscriber and send notification etc.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class EventManager {


    Map<Genre, List<EventListener>> listeners = new HashMap<>();


    public EventManager(Genre... genres) {
        for (Genre genre : genres) {
            this.listeners.put(genre, new ArrayList<>());
        }
    }


    public void subscribe(Genre genre, EventListener listener) {
        List<EventListener> users = listeners.get(genre);
        users.add(listener);
    }


    public void unsubscribe(Genre genre, EventListener listener) {
        List<EventListener> users = listeners.get(genre);
        users.remove(listener);
    }


    public void notify(Genre genre, EventDetail eventDetail) {
        List<EventListener> users = listeners.get(genre);
        for (EventListener listener : users) {
            listener.update(genre, eventDetail);
        }
    }
}

Fourthly, we should create publisher class. This class provides various operations and sends notification through these operations.

public class TicketSeller {
    
    public EventManager events;


    public TicketSeller(Genre... genres) {
        this.events = new EventManager(genres);
    }


    public void notifyEvent(Genre genre, EventDetail eventDetail) {
        events.notify(genre, eventDetail);
    }
}

Additionally, I defined an enum that name is Genre. This enum gives information about which genre supports.

public enum Genre {
    JAZZ,
    BLUES,
    ELECTRONIC
}

On the other hand, EventDetail provides sending event’s detail like when will event start?, what is the price? and which musician?

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


public class EventDetail {


    private String musician;
    private BigDecimal price;
    private LocalDateTime startTime;


    public EventDetail(String musician, BigDecimal price, LocalDateTime startTime) {
        this.musician = musician;
        this.price = price;
        this.startTime = startTime;
    }


    public String getMusician() {
        return musician;
    }


    public void setMusician(String musician) {
        this.musician = musician;
    }


    public BigDecimal getPrice() {
        return price;
    }


    public void setPrice(BigDecimal price) {
        this.price = price;
    }


    public LocalDateTime getStartTime() {
        return startTime;
    }


    public void setStartTime(LocalDateTime startTime) {
        this.startTime = startTime;
    }


    @Override
    public String toString() {
        return "Musician=" + musician + ", Price=" + price + ", Start Time=" + startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
    }
}

In the end, let’s look from client side. In the first, some subscriber are being added to salesman then salesman’s sending notifications related with events.

import java.math.BigDecimal;
import java.time.LocalDateTime;


public class Demo {
    public static void main(String[] args) {
        TicketSeller salesman = new TicketSeller(Genre.BLUES, Genre.JAZZ, Genre.ELECTRONIC);
        salesman.events.subscribe(Genre.BLUES, new SmsNotificationListener("+99 999 999 99 99"));
        salesman.events.subscribe(Genre.JAZZ, new SmsNotificationListener("+88 888 888 88 88"));
        salesman.events.subscribe(Genre.ELECTRONIC, new EmailNotificationListener("customer@ticket.com"));


        salesman.notifyEvent(Genre.BLUES, new EventDetail("Robert Johnson", BigDecimal.TEN, LocalDateTime.now()));
        salesman.notifyEvent(Genre.JAZZ, new EventDetail("Louis Armstrong", BigDecimal.TEN, LocalDateTime.now()));
        salesman.notifyEvent(Genre.ELECTRONIC, new EventDetail("Swedish House Mafia", BigDecimal.TEN, LocalDateTime.now()));
    }
}

I hope everything’s clear for you. If you don’t understand any part, feel free ask me. Also, I shared the codes I explained and more in GitHub. Additionally, certainly I recommend that you should practice with this structures. I coded these structures and these structures’ some test scenarios.


I used various resource for prepare this essay. I indicated in following. You can check out.