Observer design pattern

Last Updated on October 25, 2023 by KnownSense

In Java, the Observer pattern establishes a one-to-many dependency relationship among objects. As name suggest, we have 2 object: observer (there can be multiple observer) and observable. When an observable object changes its state, all registered observers are notified and updated automatically. This design promotes loose coupling, contributing to code maintainability and flexibility.

Benefits

The Observer pattern brings several advantages:

  1. Loose Coupling: It fosters a flexible relationship between the subject (observable) and its observers, allowing changes in one part without affecting others, thus promoting maintainability and adaptability.
  2. Extensibility: This pattern enables easy addition or removal of observers, facilitating the expansion of application functionality without altering the subject.
  3. Event-Driven Architecture: By leveraging the Observer pattern, the design embraces an event-driven approach, where changes in the observable’s state trigger actions in dependent observers, resulting in more structured and efficient code.
  4. Real-Time Updates: Observers receive prompt updates whenever the observable’s state changes, ensuring all relevant components remain synchronized.
  5. Multi-Threading Support: Proper implementation of the Observer pattern simplifies managing multi-threaded scenarios and mitigates potential race conditions.
  6. Reduced Dependencies: It reduces direct dependencies between components, leading to improved modularity and easier testing.
  7. Reusability: Observers can be repurposed in various contexts since they are independent of the observable and can be attached to different subjects.
  8. Enhanced Maintainability: Separation of concerns between the observable and observers simplifies code maintenance and debugging.

UML for observer pattern

Observer design pattern UML diagram

Implementation

In this implementation, we are creating a robust weather reporting system, with a weather station serving as the observable entity. The primary objective is to provide real-time updates on temperature changes. As soon as the temperature fluctuates, the weather station promptly sends notifications to various observing devices such as TVs and mobile devices which are observers.

Step1: create observable Interface

public interface WSObservable {
    void add(DisplayObserver displayObserver);
    void remove(DisplayObserver displayObserver);
    void notifyObserver();
    void setTemp(int newTemp);
    int getTemp();
}

Step2: create observer interface

public interface DisplayObserver {
void update();
}

Step3: create concrete class for observableInterface

public class WSObservableImpl implements WSObservable {
    List<DisplayObserver> displayObserverList = new ArrayList<>();
    int currentTemp= 0;
   
    public WSObservableImpl() {

    }
   
    @Override
    public void add(DisplayObserver displayObserver) {
        displayObserverList.add(displayObserver);
    }
    
    @Override
    public void remove(DisplayObserver displayObserver) {
      displayObserverList.remove(displayObserver);
    }
   
    @Override
    public void notifyObserver() {
      for (DisplayObserver obj : displayObserverList){
          obj.update();
      }
    }
    
    @Override
    public void setTemp(int newTemp) {
         currentTemp=newTemp;
         notifyObserver();
    }
    
    @Override
    public  int getTemp(){
        return currentTemp;
    }
}

Step4: create concrete class for observerInterface for TV and mobile both

public class DisplayMobileObserver implements  DisplayObserver{
    WSObservable observable;
    String mobileNumber;

    public DisplayMobileObserver(String mobile,WSObservable observable) {
        this.observable = observable;
        this.mobileNumber=mobile;
    }

    @Override
    public void update() {
      sendMail(mobileNumber,"temp= "+ observable.getTemp()+ " sent to ");
    }

    void sendMail(String mobile, String msg){
        System.out.println(msg+ " : "+ mobile);
    }
}
public class DisplayTVObserver implements DisplayObserver{
    WSObservable observable;

    String TvChannel;

    public DisplayTVObserver(String TVChannel,WSObservable observable) {
        this.observable = observable;
        this.TvChannel=TVChannel;
    }

    @Override
    public void update() {
       sendMail( TvChannel,"temp= "+ observable.getTemp()+ " sent to ");
    }
    void sendMail(String TvChannel, String msg){
        System.out.println(msg +" : "+ TvChannel);
    }
}

Step5: In the main class create the observable and add the obeservers

public class ObDesignpattern {

    public static void main(String args[]){
        WSObservable wsObservable = new WSObservableImpl();
        DisplayObserver displayObserver = new DisplayMobileObserver("8658344312", wsObservable);
        DisplayObserver displayObserver1 = new DisplayTVObserver("ABP", wsObservable);
        wsObservable.add(displayObserver);
        wsObservable.add(displayObserver1);
        wsObservable.setTemp(60); //temp change
        wsObservable.setTemp(70); //again temp change
    }
}

Output:
temp= 60 sent to : 8658344312
temp= 60 sent to : ABP
temp= 70 sent to : 8658344312
temp= 70 sent to : ABP

Conclusion

In conclusion, the Observer design pattern is a powerful and versatile architectural solution that facilitates effective communication and coordination between objects in a one-to-many relationship. By implementing this pattern, developers can achieve loose coupling, enhancing code flexibility, reusability, and maintainability. The Observer pattern’s event-driven approach enables real-time updates and seamless integration of multiple observers, making it particularly valuable in scenarios where timely information dissemination is crucial.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top