Edit Page

Lab 9: The Observer Design Pattern

The goal of this lab is to use the observer design pattern to solve a real-world problem.

Design patterns are proven solutions to solve recurring design problems to design flexible and reusable object-oriented software; that is, objects that are easier to implement, change, test and reuse. Behavioral pat­terns deal with the communication between objects and structuring the responsibilities between objects to keep­ them extensible, flex­i­ble and efficient.

The observer design pattern (a.k.a. dependency broadcasting, publish-subscribe pattern) is one of the twenty-three well-known Gang of Four (GoF) design patterns. It is classified under the category of behavioral patterns. The observer design pattern allows us to implement a subscription service in which an object called the subject maintains a list of dependent objects called observers. The subject notifies the observers of a change to the subject’s state and broadcasts the change to them by calling the observers’ methods. In the observer pattern, a subject maintains a list of observers and notifies them of any state changes, without the need for the subject to keep track of the observers.

In this lab, we will work on the problem of creating a notification system in which a message needs to be broadcasted to multiple subscribers.

Video

Objectives

In this lab you will

  1. understand a real-world scenario and choose when to apply the appropriate design pattern.
  2. design and implement the observer design pattern.

Requirement and Tools

Getting Started

If your instructor is using GitHub classroom, you will need to accept the assignment using the link below, clone the template repository, and import it as a project into your IDE.

If your instructor is not using GitHub classroom, clone and import the template project at https://github.com/cpit252/lab-09 ↗.

Problem Statement

A developer is working on an app that monitors the price of a product on an online store. The app allows users to receive a notification when the price of a given product drops. These notifications can be received via Email, Facebook, Whatsapp, SMS, etc. He wanted to support multiple notification services in the future. Thus, his design goal is to build up a system that is extensible and efficient where he can add a new notification service (e.g, push notification, Voice calls, etc.) without making additional changes to existing working services.

Below is the web page he wants to regularly check the price on:

The Subjects

Subject.java

1
2
3
4
5
public interface Subject{
    public void subscribe(Observer o);
    public void unsubscribe(Observer o);
    public void notifyUpdate(String m);
}

Subject.java

1
2
3
4
public class MessageSubject implements Subject {
     
 
}

The Observers

Observer.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public abstract class Observer {
    private String recipient;

    public String getRecipient() {
        
    }

    public void setRecipient(String recipient) {

    }

    public abstract void update(String m);
}

FacebookObserver.java

1
2
public class FacebookObserver extends Observer{
}

WhatsappObserver.java

1
2
3
public class WhatsappObserver extends Observer{

}

EmailObserver.java

1
2
3
public class EmailObserver extends Observer{

}

App.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class App {

    private static String searchForProduct(String keyword){
        try (Playwright playwright = Playwright.create()) {
            // Launch Chromium in headless mode
            Browser browser = playwright.chromium().launch();
            Page page = browser.newPage();
            // Navigate and scrape product titles and prices
            page.navigate("https://cpit252.gitlab.io/html/lab-8/");
            List<String>  products = page.locator("h2.title").allInnerTexts();
            List<String>  prices = page.locator("p.price").allInnerTexts();
            for (int i=0; i< products.size(); i++) {
                if(products.get(i).indexOf(keyword) > -1) {
                    return products.get(i) + " " + prices.get(i);
                }
            }
            return null;
        }
    }
    public static void main(String[] args) {
        Observer fbObserver = new FacebookObserver("CPIT_252_price_watcher");
        Observer emailObserver = new EmailObserver("email@example.com");
        Observer waObserver = new WhatsappObserver("9660000000000");

        Subject s = new MessageSubject();

        s.subscribe(fbObserver);
        s.subscribe(emailObserver);
        // Get the price of a product (e.g., MacBook)
        String message = searchForProduct("MacBook");
        s.notifyUpdate(message);

        System.out.println("\nChange observers: unsubscribed email and subscribed Whatsapp\n");
        s.unsubscribe(emailObserver);
        s.subscribe(waObserver);

        s.notifyUpdate(message);
    }
}

Questions:

  1. Complete the implementation of the observer design pattern as shown in the code above?
  2. Explain how the observer design pattern simplified the process of adding a new notification service in this implementation?
  3. [Optional] Store the prices in a database or a cache such as Ehcache.

Deliverables and Submission

Extra Task [Optional]

If you are done with this activity, you may enable a continuos integration tool such as CircleCI ↗ to automatically run your JUnit test upon code changes. You may also add more unit tests to increase code coverage. Please embed the badge that shows the status of your build and test (passing/failing) as well as the coverage percentage into your README file (e.g., passing status image and failing status image). Please be sure to fork the repository or push to a remote repository under your own account, so you can enable the integration of CI tools in your own account.

You may refer to the lecture notes from the prerequisite course CPIT-251 on Continuous Integration (CI) and adding a code coverage badge.