[GO] Observer pattern understood by cats Part 1

Overview

The Observer pattern is confusing, isn't it? So I would like to explain this pattern with the example of two cats begging for rice. IMG_0751.JPG

Nyanko to appear

** Tama of domestic cat ** Tama lives on the 3rd floor of an apartment. The owner lives alone. The windows are often closed and you don't go out and play. neko_furikaeri.png

** Stray cat tiger ** A tiger lives in a shopping district. I go to cat lovers' houses and catch garbage to secure food. run_cat.png

I think this is probably the simplest Observer pattern

Cat.java


public class Cat{//Subject class
    private Human human;
    
    public void setHuman(Human human){// setObserver()
        this.human = human;
    }

    public void call(){// notifyObservers()
        System.out.println("Nya (I'm hungry)");
        this.human.called();
    }
}

Human.java


public class Human{//Observer class
    public void called(){// notify() or update()
        System.out.println("Give crunchy");
    }
}

Main.java


    public static void main(String[] args) {
        Cat tama = new Cat();
        Human master = new Human();
        tama.setHuman(master);

        tama.call();
    }
Nya (I'm hungry)
Give crunchy

Commentary

uml1.png

There are two main points of the Observer pattern. The first is that the Subject class has an Observer class as a member variable. In other words, Tama (Cat class) needs to know the owner (Human class). This is represented by the setHuman (= setObserver) function. The second is to call the Observer class when the Subject class changes. In other words, if you are hungry, you will call the owner. This is represented by the Cat.call and Human.called functions.

However, in the simplest Observer pattern, Tama can only remember one owner. When you try to remember another person, you forget about the owner. The owner will have teary eyes.

Main.java


    public static void main(String[] args) {
        Cat tama = new Cat();
        Human master = new Human();
        tama.setHuman(master);

        //The owner's friend came to play
        Human friend = new Human();
        tama.setHuman(friend);

        //After that, you will be asking your friend for food.
        tama.call();
    }

Basic structure of Observer pattern

Tigers can do things that Tama couldn't. Tigers remember various homes and seem to go around them every time they are hungry.

Cat.java


public class Cat {//Subject class
    private final ArrayList<Human> humans = new ArrayList<>();
    
    public void addHuman(Human human){// addObserver()
        this.humans.add(human);
    }

    public void deleteHuman(Human human){// deleteObserver()
        this.humans.remove(human);
    }

    public void call(){// notifyObservers()
        System.out.println("Nya (I'm hungry)");
        for(Human human : this.humans){
            human.called();
        }
    }
}

Human.java


public class Human {//Observer class
    public void called(){// notify() or update()
        int dice = new Random().nextInt(99);

        if(dice < 50){
            System.out.println("This is for you!");
            
        } else {
            System.out.println("There is nothing today ...");
        }
    }
}

Main.java


public static void main(String[] args) {
    Cat tora = new Cat();
    Human suzuki = new Human();
    Human saito = new Human();
    Human kobayashi = new Human();

    tora.addHuman(suzuki);
    tora.addHuman(saito);
    tora.addHuman(kobayashi);

    tora.call();
}
Nya (I'm hungry)
There is nothing today ...
This is for you!
There is nothing today ...

Commentary

uml2.png

There are three particularly important differences between the Tama and Tiger codes. First, the member variable of the Subject class is now an ArrayList. This allows tigers to beg for food under the eaves of multiple homes. Second, the function of the Subject class has changed from setObserver to addObserver. The name has been changed because it is now possible to set multiple elements instead of a single element. Third, you can now not only register the Observer class, but also delete it. The deleteObserver function demonstrates its role. Non-owners have a 50% chance of feeding, but not the remaining 50%. It's hard to know, but I may not go to a house that doesn't feed much (not implemented).

Generalization

Make the tiger code more versatile and versatile. Then it will be in the form of the Observer pattern you often see.

Subject.java


public class Subject {
    private final ArrayList<Observer> observers = new ArrayList<>();
    
    public void addObserver(Observer observer){
        this.observers.add(observer);
    }

    public void deleteObserver(Observer observer){
        this.observers.remove(observer);
    }

    public void notifyObservers(){
        for(Observer observer : this.observers){
            observer.update();
        }
    }
}

Cat.java


public class Cat extends Subject {
    @Override
    public void notifyObservers(){
        System.out.println("Nya (I'm hungry)");
        super.notifyObservers();
    }
}

Observer.java


public interface Observer{
    public void update(); // or notify()
}

Human.java


public class Human implements Observer{
    @Override
    public void update(){
        int dice = new Random().nextInt(99);

        if(dice < 50){
            System.out.println("This is for you!");
            
        } else {
            System.out.println("There is nothing today ...");
        }
    }
}

Main.java


public static void main(String[] args) {
    Cat tora = new Cat();
    Human suzuki = new Human();
    Human saito = new Human();
    Human kobayashi = new Human();

    tora.addObserver(suzuki);
    tora.addObserver(saito);
    tora.addObserver(kobayashi);

    tora.notifyObservers();
}
Nya (I'm hungry)
This is for you!
This is for you!
There is nothing today ...

Commentary

uml3.png

There are three generalizations and changes to the tiger code. First, the Human class now implements the Observer interface. The reason for sandwiching the Observer interface is explained with the third change. Second, I extracted the functions of the Cat class as the Subject class. This makes the Cat class, which is volatile, simpler. Third, we now include the Observer interface in the Subject class ArrayList instead of the Human class. By calling the Observer.update function, you can call the update function of various classes as well as the Human class, which makes it more versatile.

Supplement

  1. The update function, which sometimes appears as a notify function, shows the same functionality.
  2. In java, the Subject class is the Observable class and the Observer interface has the same name. I have prepared it.
  3. The Subject class is sometimes called the Event Handler, and the Observer class is sometimes called the Event Listener.

in conclusion

This commentary is for those who have just started studying design patterns but find the Observer pattern difficult. If you read this commentary and then read the class diagram and other commentary again, it will be easier to understand what this pattern is trying to do. Please also read Part 2 if you like. Also, I would appreciate your comments and likes.

Recommended Posts

Observer pattern understood by cats Part 1
Observer pattern understood by Nyanko Part 2
Design Pattern #Observer
Observer pattern in Java
Sample source of Observer pattern realized by Java, PHP, Python
Making sound by programming Part 2