Observer Design Pattern Overview
- When a subject changes state, it notifies all the subscribers (one to many relationship).
Before
public class GranaryData {
private BarChart barChart;
private PieChart pieChart;
private int _bread;
private int _meat;
private int _cheese;
int getTotalBread() { return _bread; }
int getTotalMeat() { return _meat; }
int getTotalCheese() { return _cheese; }
public GranaryData() {
barChart = new BarChart();
pieChart = new PieChart();
}
public void setStock(int bread, int meat, int cheese) {
_bread = bread;
_meat = meat;
_cheese = cheese;
notifySubscriber();
}
private void notifySubscriber() {
/* This method is called whenever food stock (bread, meat, cheese) is modified. */
int bread = getTotalBread();
int meat = getTotalMeat();
int cheese = getTotalCheese();
barChart.update(bread, meat, cheese);
pieChart.update(bread, meat, cheese);
}
}
public class BarChart {
public void update(int bread, int meat, int cheese) {
String display = '(BarChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
public class PieChart {
public void update(int bread, int meat, int cheese){
String display = '(PieChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
public class Simulator {
public static void main(String[] args) {
GranaryData granary = new GranaryData();
granary.setStock(1, 2, 3); //simulate food stock update.
//displays... (Bar Chart) Bread: 1 | Meat: 2 | Cheese: 3
//displays... (Pie Chart) Bread: 1 | Meat: 2 | Cheese: 3
}
}
After #1 (Push Method)
- The subscribers are provided data from the publisher via update function parameter.
- 1 or more displays (bar/pie) can subscribe and unsubscribe during runtime.
- Adding/Removing subscribers from publisher does not changes publisher’s class.
interface Publisher {
void addSubscriber(Subscriber s);
void removeSubscriber(Subscriber s);
void notifySubscriber();
}
interface Subscriber {
void update(Map data);
}
public class BarChart implements Subscriber {
@Override
void update(Map data) {
int bread = data.bread;
int meat = data.meat;
int cheese = data.cheese;
String display = '(BarChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
public class PieChart implements Subscriber {
@Override
void update(Map data) {
int bread = data.bread;
int meat = data.meat;
int cheese = data.cheese;
String display = '(PieChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
public class GranaryData implements Publisher {
private ArrayList subscribers;
private int _bread;
private int _meat;
private int _cheese;
int getTotalBread() { return _bread; }
int getTotalMeat() { return _meat; }
int getTotalCheese() { return _cheese; }
public GranaryData() {
subscribers = new ArrayList();
}
public void setStock(int bread, int meat, int cheese) {
_bread = bread;
_meat = meat;
_cheese = cheese;
notifySubscriber();
}
@Override
void addSubscriber(Subscriber s) {
int index = subscribers.indexOf(s);
if (index == -1) subscribers.add(s);
}
@Override
void removeSubscriber(Subscriber s) {
int index = subscribers.indexOf(s);
if (index > -1) subscribers.remove(index);
}
@Override
void notifySubscriber() {
/*This method is called whenever food stock (bread/meat/cheese) is modified. */
int bread = getTotalBread();
int meat = getTotalMeat();
int cheese = getTotalCheese();
Map data = new HashMap();
data.bread = bread;
data.meat = meat;
data.cheese = cheese;
int i = subscribers.size();
while (i--) {
subscribers[i].update(data);
}
}
}
public class Simulator {
public static void main(String[] args) {
GranaryData granary = new GranaryData();
BarChart barChart = new BarChart();
PieChart pieChart = new PieChart();
granary.addSubscriber(barChart);
granary.addSubscriber(pieChart);
granary.setStock(1, 2, 3); //simulate food stock update.
//displays... (Bar Chart) Bread: 1 | Meat: 2 | Cheese: 3
//displays... (Pie Chart) Bread: 1 | Meat: 2 | Cheese: 3
granary.removeSubscriber(barChart);
granary.setStock(4, 5, 6); //simulate food stock update.
//displays... (Pie Chart) Bread: 4 | Meat: 5 | Cheese: 6
}
}
After #2 (Pull Method)
- The subscribers retrieve data directly from the publisher’s class via function calls.
- 1 or more displays (bar/pie) can subscribe and unsubscribe during runtime.
- Adding/Removing subscribers from publisher does not changes publisher’s class.
interface Publisher {
void addSubscriber(Subscriber s);
void removeSubscriber(Subscriber s);
void notifySubscriber();
}
interface Subscriber {
void update(Publisher p);
}
public class BarChart implements Subscriber {
@Override
void update(Publisher p) {
if (p instanceof GranaryData) {
GranaryData granary = (GranaryData) p;
int bread = granary.getTotalBread();
int meat = granary.getTotalMeat();
int cheese = granary.getTotalCheese();
String display = '(BarChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
public class PieChart implements Subscriber {
@Override
void update(Publisher p) {
if (p instanceof GranaryData) {
GranaryData granary = (GranaryData) p;
int bread = granary.getTotalBread();
int meat = granary.getTotalMeat();
int cheese = granary.getTotalCheese();
String display = '(PieChart) Bread: ' + bread + ' | Meat: ' + meat + ' | Cheese: ' + cheese;
System.out.println(display);
}
}
}
public class GranaryData implements Publisher {
private ArrayList subscribers;
private int _bread;
private int _meat;
private int _cheese;
int getTotalBread() { return _bread; }
int getTotalMeat() { return _meat; }
int getTotalCheese() { return _cheese; }
public GranaryData() {
subscribers = new ArrayList();
}
public void setStock(int bread, int meat, int cheese) {
_bread = bread;
_meat = meat;
_cheese = cheese;
notifySubscriber();
}
@Override
void addSubscriber(Subscriber s) {
int index = subscribers.indexOf(s);
if (index == -1) subscribers.add(s);
}
@Override
void removeSubscriber(Subscriber s) {
int index = subscribers.indexOf(s);
if (index > -1) subscribers.remove(index);
}
@Override
void notifySubscriber() {
/*This method is called whenever food stock (bread/meat/cheese) is modified. */
int i = subscribers.size();
while (i--) {
subscribers[i].update(this);
}
}
}
public class Simulator {
public static void main(String[] args) {
GranaryData granary = new GranaryData();
BarChart barChart = new BarChart();
PieChart pieChart = new PieChart();
granary.addSubscriber(barChart);
granary.addSubscriber(pieChart);
granary.setStock(1, 2, 3); //simulate food stock update.
//displays... (Bar Chart) Bread: 1 | Meat: 2 | Cheese: 3
//displays... (Pie Chart) Bread: 1 | Meat: 2 | Cheese: 3
granary.removeSubscriber(barChart);
granary.setStock(4, 5, 6); //simulate food stock update.
//displays... (Pie Chart) Bread: 4 | Meat: 5 | Cheese: 6
}
}