Observer

What is the Observer Pattern?

The Observer Pattern is a behavioral design pattern used to create a one-to-many dependency between objects. When one object (the subject) changes its state, all its dependents (observers) are automatically notified and updated.

It is also known as Publish-Subscribe or Event Listener pattern.


Why Use Observer in FRC Robot Code?

Robotics is highly event-driven: sensors change, user inputs happen, and robot states update constantly. The Observer pattern helps by:

  • Decoupling event sources from event handlers.

  • Allowing multiple parts of code (observers) to react to changes without tight coupling.

  • Keeping your code modular and maintainable.

  • Making asynchronous or reactive programming easier, like reacting to joystick buttons or sensor triggers.

  • Facilitating communication between subsystems and dashboard updates.


Core Concepts

  • Subject: The object holding state or events that observers want to watch.

  • Observer: Objects that subscribe to the subject to get notified of state changes.

  • Notification: When the subject changes, it calls each observer’s update method.


Typical Use Cases in FRC

  • Sensor Monitoring: Observers react when a sensor value crosses a threshold.

  • Joystick/Button Events: Buttons act as subjects that notify commands or subsystems.

  • Robot State Changes: Observers update dashboard or loggers when mode changes.

  • Vision Processing: Vision subsystem publishes detected targets; other code reacts.

  • Subsystem Feedback: E.g., Elevator position changes notify other parts of code.


Example: Simple Observer Implementation for Sensor Changes

Step 1: Define the Observer interface

public interface Observer {
    void update();
}

Step 2: Define the Subject interface

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

Step 3: Implement a concrete Subject — e.g., a LimitSwitch sensor wrapper

import java.util.ArrayList;
import java.util.List;

public class LimitSwitch implements Subject {
    private boolean state;
    private final List<Observer> observers = new ArrayList<>();

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

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update();
        }
    }

    public void setState(boolean newState) {
        if (state != newState) {
            state = newState;
            notifyObservers();
        }
    }

    public boolean getState() {
        return state;
    }
}

Step 4: Implement an Observer — e.g., a command or subsystem watching the switch

public class ElevatorController implements Observer {
    private final LimitSwitch limitSwitch;

    public ElevatorController(LimitSwitch limitSwitch) {
        this.limitSwitch = limitSwitch;
        limitSwitch.registerObserver(this);
    }

    @Override
    public void update() {
        if (limitSwitch.getState()) {
            System.out.println("Limit switch activated! Stopping elevator.");
            // Stop elevator motor here
        }
    }
}

These are less used in out codebase, there are areas where they should be applied where they havent been yet

Last updated