Ayumilove Observer Design Pattern

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
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *