DEV Community

Henri Idrovo
Henri Idrovo

Posted on • Originally published at henricodesjava.blog on

Design Patterns: Observer Pattern

originally posted on my blog at henricodesjava.blog

Hi everyone! Chapter two in Head First Design Patterns: A Brain-Friendly Guide is all about the Observer Pattern. They make note of how fundamental and frequently this pattern is used. And also allude to the idea that future patterns in this book are based on this and other pattern combinations. So lets talk about the Observer Pattern.

The problem this pattern is trying to solve is about communication and management. A simple abstract example given in the text is about a newspaper publishing company, and its subscribers. Technically this relationship can be categorized as a ONE-TO-MANY relationship, one publisher, and many subscribers. The text uses the term ‘ Subject ‘ to refer to the publisher, and the term ‘ Observer ‘ to refer to the subscribers.

Next I’ll give a more concrete example. I’ll use an example slightly different from the text to help illustrate the idea. Lets say we are a finance startup, and we have an idea for a smartwatch app that can communicate with all your financial institutions to give you a bird’s eye view of your finances. For example it can show you balances of your checking account, or show you prices of stocks you own. What we have access to is a class that can return these values for us, lets call this class FinancialData. For the purposes of this example, we don’t care how it retrieves this information.

Screen Shot 2017-09-30 at 12.28.17 AM.png

Below is a naive implementation of our smart watch app, along with an explanation. Of course all of this is just pseudo code, no actual smartwatch code.

Screen Shot 2017-09-30 at 1.24.50 AM.png

There are a few things wrong with this implementation. First we are in violation of a design principle from back in chapter one. _Identify the aspect of your application that vary and separate them from what stays the same. _The lines with the green arrows represent a different screen on the watch, and in the future we might want to add more screens. When that times comes, changes to this class are unfortunately unavoidable. The lines with red arrows are retrieving financial data, and while this too can change, it would be a change caused by a API change and not a change on our client side code. We are also in violation of another design principle: _Program to an interface, not an implementation. _If only there was a way we can neatly separate code that changes, from code that doesn’t, and also not program to an implementation? Introducing, the Observer pattern!

The Observer Pattern : Defines a one-to-many dependency between objects so that when one object changes state, all of it’s dependents are notified and updated automatically.

We will accomplish this, and introduce loose coupling by the use of interfaces. Lets illustrate this definition with a class diagram.

Screen Shot 2017-09-30 at 10.56.06 AM

 

Now with these class diagrams as a guide, lets take a look at an implementation for our smart watch app. First the two interfaces are below.

public interface Subject {
    public void registerObserver(Observer o);
    public void removeObserver(Observer o);
    public void notifyObservers();
}

public interface Observer {
    public void upate(Object obj);
}
Enter fullscreen mode Exit fullscreen mode

 

Next lets take a look at our new FinancialData class that implements the Subject interface.

public class FinancialData implements Subject {
   private ArrayList observers;

   private float checkingBalance;
   private float savingsBalance;

   private float stockValue;
   private float fourOnekValue;

   private float weekSpending;
   private float monthSpending;

   public FinancialData(){
      observers = new ArrayList();
   }

   public void registerObserver(Observer o){
      observers.add(o);
   }

   public void removeObserver(o){
      int i = observers.indexOf(o);
      if(i > 0){
         observers.remove(i);
      }
   }

   public void notifyObservers(){
      for(int i = 0; i<observers.size(); i++){
         Observer observer = (Observer)observers.get(i);
         observer.update(this);
      }
   }

   public void measurementsChanged(){
      notifyObservers();
   }

   public void setNewBalanceData(float val1, float val2){
      this.checkingBalance = val1;
      this.savingsBalance = val2;
      measurementsChanged();
   }

   public void setNewInvestmentData(float val1, float val2){
      this.stockValue = val1;
      this.fourOnekValue = val2;
      measurementsChanged();
   }

   public void setNewSpendingData(float val1, float val2){
      this.weekSpending = val1;
      this.monthSpending = val2;
      measurementsChanged();
   }
   // other FinancialData methods here
   // including getter methods for balance, investment, and spending values
}
Enter fullscreen mode Exit fullscreen mode

 

Now lets take a look at one of our observers, the Balance smart watch screen.

public class BalanceScreen implements Observer {
   private float checkingBal;
   private float savingsBal;
   private Subject financialData;

   public BalanceScreen(Subject financialData){
      this.financialData = financialData;
      financialData.registerObserver(this);
   }

   public void update(Object obj){
      if( obj instanceof FinancialData){
         FinancialData fd = (FinancialData) obj;
         this.checkingBal = fd.getCheckingBalance();
         this.savingsBal = fd.getSavingsBalance();
      }
      display();
   }
   // other BalanceScreen methods here
}
Enter fullscreen mode Exit fullscreen mode

Finally lets take a look at a program to glue all this together.

public class SmartWatch {
    public static void main(String[] args){
        FinancialData financialData = new FinancialData();

        BalanceScreen balanceScreen = new BalanceScreen(financialData);
        InvestmentScreen investmentScreen = new InvestmentScreen(financialData);
        SpendingScreen spendingScreen = new SpendingScreen(financialData);

        // not using an actualy finance api, so we set values manually
        financialData.setNewBalanceData(348.12, 3600.87);
        financialData.setNewInvestmentData(899.12, 45000.65);
        financialData.setNewSpendingData(210.34, 677.45);

        // at this point we should see print statements for all 3 screens
    }
}
Enter fullscreen mode Exit fullscreen mode

There you have it! We implemented the interfaces and created some code to test it. Now please note I haven’t actually got this code running, so there might be a bug or two in these lines. For a future post I’ll have to create a project and push this working code up on github. Thanks for reading !👋🏽

(originally posted at my personal blog: https://henricodesjava.blog)

Top comments (4)

Collapse
 
marlysson profile image
Marlysson Silva

Just observers knows your target ( Subject ) ? In a relation of One to One ( with direction just observer -> subject , without get back )

I think ( in my opinion ) that the subject had a list of observers and in your update performed the method to notify them..

But seing your implementation , you give the responsability to observers of receive the subject and into constructor of the observer call the subject and run the .registerObserver() method. Why this choice?

Summary: Why the each observer know your subject and not one subject knows your observers ( having a list of them );

Great article.

Collapse
 
henriavo profile image
Henri Idrovo • Edited

Good question Marlysson! I had the same thought when I was reading this chapter. The text doesn’t mention why they chose this design. But they did give another example of the Observer pattern implementation in the JDK, specifically in Swing. And in this example, the Subject constructor take an Observer, and registers it as an observer. So I guess it’s flexile?

Collapse
 
marlysson profile image
Marlysson Silva

I agree. When I was studying these patterns emerged the same doubt. I think there are severals design to implement observer pattern, each one suitable to right problem.

Collapse
 
henriavo profile image
Henri Idrovo • Edited

One thing I noticed after I published this. Not all observers are receiving the same data. An ideal example for the Observer patten would be if all the smart watch screens received and did something unique with the same data 🤷🏽‍♂️