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); } }
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*'