# Observer Design Pattern explained in 2 minutes

### Problem Statement

Imagine, you have a pool of workers and a set of jobs that need execution. How are you going to model it?

```java
class Job {
    List<Worker> workers = new ArrayList<>();
    
    public void executeJob() {
        workers.forEach(worker -> worker.execute(this))
    }
}
```

The simplest strategy is to pass a list of workers to the Job and then invoke them one by one during execution.

The downside of this approach is that it tightly couples two different concepts - job and its execution together in the same class. It's assigning multiple responsibilities to the same class which violates SRP (Single Responsibility Principle).

Observer Design Pattern can simplify this solution!

```java
public record Job(String jobId) {
}

public interface Observer<T> {
    void update(T data);
}

public interface Subject<T> {
    boolean addObserver(Observer<T> observer);

    boolean removeObserver(Observer<T> observer);

    void notifyObservers(T data);
}

public class JobDispatcher implements Subject<Job> {
    Set<Observer<Job>> observers = new HashSet<>();

    @Override
    public boolean addObserver(Observer<Job> observer) {
        return observers.add(observer);
    }

    @Override
    public boolean removeObserver(Observer<Job> observer) {
        return observers.remove(observer);
    }

    @Override
    public void notifyObservers(Job job) {
        observers.forEach(observer -> observer.update(job));
    }
}

public class JobExecutor implements Observer<Job> {
    UUID uuid;

    public JobExecutor() {
        uuid = UUID.randomUUID();
    }

    @Override
    public void update(Job data) {
        System.out.println(uuid + " is executing jobId " + data.jobId());
    }
}

public class Main {
    public static void main(String[] args) {
        testObserver();
    }

    public static void testObserver() {
        JobExecutor executor1 = new JobExecutor();
        JobExecutor executor2 = new JobExecutor();
        JobDispatcher jobDispatcher = new JobDispatcher();
        jobDispatcher.addObserver(executor1);
        jobDispatcher.addObserver(executor2);
        jobDispatcher.notifyObservers(new Job("job1"));

        jobDispatcher.removeObserver(executor1);
        jobDispatcher.notifyObservers(new Job("job2"));
    }
}

// Output
3139088c-07eb-4f92-92da-0fb3af53b6be is executing jobId job1
fea0bf8a-6b2e-413f-9ae9-4a286b142798 is executing jobId job1
fea0bf8a-6b2e-413f-9ae9-4a286b142798 is executing jobId job2
```

We have created two new interfaces, `Observer` and the `Subject`. The sole responsibility of the `Observer` is to act when a subject is modified. The subject keeps track of the list of observers and decides how/when to invoke them when it changes.

### What's the benefit?

* Adheres to SRP - Each class has one responsibility and is decoupled from another. The logic of execution can change without impacting the subject.
    

### What's the drawback?

* This design pattern is very similar to the Publisher/Consumer problem and hence it suffers from all its issues as well. In a production ready code, we would have to be agnostic of various conditions like how to deal with slow observers, backpressure propagation and task backlog management.
