Module 1: Design Pattern: Observer and State

Module Overview

Learn about the Observer design pattern and state management in Java. The Observer pattern allows objects to notify other objects about changes in their state, which is valuable for building loosely coupled systems.

Learning Objectives

  • Understand the Observer Pattern
    • Understand Observers
    • Understand Sources
    • Understand when and how sources interact with and update observers
  • Be able to implement an observer pattern in an existing application
  • Understand how the observer pattern helps make fewer costly calls to a database
  • Understand real life examples of when you would want to use an observer pattern
  • Understand the utility of defining and implementing an interface

About the Observer Pattern

The Observer design pattern defines a dependency among cooperating objects so that when one object's state changes, all dependent objects are notified automatically. This pattern is commonly used in event handling systems, social media notifications, and many other applications where loose coupling between components is important.

Elements of the Observer Pattern

The Observer pattern consists of four distinct elements:

  • Subject - An interface or abstract class that defines methods for attaching, detaching, and notifying observers
  • Observer - An interface or abstract class with an update method that gets called when the subject's state changes
  • Concrete Subject - A class that implements the Subject interface and maintains a list of observers
  • Concrete Observer - A class that implements the Observer interface and registers with a Concrete Subject to receive updates

Example Implementation

Here's how you might implement a simple Observer pattern in Java:

// Subject interface
public interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// Observer interface
public interface Observer {
    void update();
}

// Concrete Subject
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String state;
    
    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }
    
    public String getState() {
        return state;
    }
    
    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

// Concrete Observer
public class ConcreteObserver implements Observer {
    private ConcreteSubject subject;
    private String observerState;
    
    public ConcreteObserver(ConcreteSubject subject) {
        this.subject = subject;
        subject.attach(this);
    }
    
    @Override
    public void update() {
        observerState = subject.getState();
        System.out.println("Observer state updated to: " + observerState);
    }
}

Guided Projects

Setup your Sprint 8 Challenge Repo

This Sprint culminates in a Sprint Challenge project. You should begin by forking and cloning the Sprint Challenge starter repo:

This will be your project repo for Sprint 8.

This resource is also visible under the Sprint Challenge section of the course page. After each module, you will be assigned a mastery task with instructions on adding to or modifying the starter code for the challenge. Upon completion of all mastery tasks, the Sprint Challenge project will be complete and ready for you to submit to CodeGrade. The CodeGrade submission page is available under the Sprint Challenge section on the modules page.

Mastery Task 1: Implement Observer Pattern

Mastery Task Guidelines

Mastery Tasks are opportunities to test your knowledge and understanding through code. When a mastery task is shown in a module, it means that we've covered all the concepts that you need to complete that task.

Each mastery task must pass 100% of the automated tests and code styling checks to pass each sprint. Your code must be your own. If you have any questions, feel free to reach out for support.

The Observer and Source interfaces have been provided for you already. Your task is to implement these interfaces in the OUserFeed and SourceFeed classes.

You will also want to attach the user's feed to the SourceFeed after instantiation.

The one and only SourceFeed instance is initialized from with App. You can make global references to this instance during your implementation. You should not create any other SourceFeed instances.

Completion

The SourceFeed should be allow Observer's to attach and detach, and it should call each observer's update method from its updateAll method.

Each OUserFeed observer instance should attach to the source feed and should contain a list of Posts of only the users the user who owns the feed is following.

All tests should pass after running the following command:

./gradlew -q clean :test --tests 'com.bloomtech.socialfeed.MT01*'

Resources