Walk into observer mode together

Posted by Shawn Jetton on Sun, 09 Jan 2022 10:10:46 +0100

I introduce

Observer Pattern is a behavioral pattern. The one to many dependency between objects is defined to allow multiple observers to listen to a topic object at the same time. Similar to the broadcast mechanism, it only needs to distribute the broadcast, and the interested objects automatically receive the broadcast. What we usually call observer, Listener, Hook and Callback are all related to this mode

II Scene constraints

When a child cries, he will notify his father and his mother, who will take different actions

III UML class diagram

Version one

Version 2
The new event class decouples the observer from the topic. The observer can perform different operations according to different events or directly operate the event source

IV Schematic code (version 1)

Business code

//Abstract observer
public interface Observer {
    void action();
}

//Abstract theme
abstract class Subject{
    protected List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

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

    public abstract void notifyObserver();
}

//Specific subject - observed
class Baby extends Subject{
    @Override
    public void notifyObserver() {
        System.out.println("baby cry");
        observers.forEach(Observer::action);
    }
}

//Specific observer
class Dad implements Observer {
    @Override
    public void action() {
        System.out.println("dad feed baby");
    }
}

//Specific observer
class Mum implements Observer {
    @Override
    public void action() {
        System.out.println("mum hug baby");
    }
}

client

public class Client {
    public static void main(String[] args) {
        Baby baby = new Baby();
        baby.addObserver(new Mum());
        baby.addObserver(new Dad());
        baby.notifyObserver();
    }
}

V Schematic code (version 2)

//Abstract observer
public interface Observer {
    void action(Event event);
}

//Abstract theme
abstract class Subject {
    protected List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

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

    public abstract void notifyObserver();
}

//Specific subject - observed
class Baby extends Subject {
    @Override
    public void notifyObserver() {
        System.out.println("baby cry");
        CryEvent cryEvent = new CryEvent(new Date().getTime(), this);
        observers.forEach(observer -> observer.action(cryEvent));
    }
}

//Abstract event
abstract class Event {
    public abstract Object getSource();
}

//Specific events
class CryEvent extends Event {
    public long when;
    Baby source;

    public CryEvent(long when, Baby source) {
        this.when = when;
        this.source = source;
    }

    @Override
    public Baby getSource() {
        return source;
    }
}

//Specific observer
class Dad implements Observer {
    @Override
    public void action(Event event) {
        System.out.println("dad feed baby");
        if(event.getSource() instanceof Baby){
            System.out.println("dad Process the event source");
        }
    }
}

//Specific observer
class Mum implements Observer {
    @Override
    public void action(Event event) {
        System.out.println("mum hug baby");
        if(event.getSource() instanceof Baby){
            System.out.println("mum Process the event source");
        }
    }
}

client

public class Client {
    public static void main(String[] args) {
       Baby baby = new Baby();
       baby.addObserver(new Dad());
       baby.addObserver(new Mum());
       baby.notifyObserver();
    }
}

Vi Observer mode and publish subscribe mode


Publish subscribe mode

  • Publishers do not notify subscribers directly
  • Publishers and subscribers are completely decoupled

Observer mode

  • The subject should notify the observer by itself
  • Loose coupling between subject and observer

VII advantage

  • Comply with the dependency inversion principle (both observers and topics rely on abstraction)
  • Reduce coupling (coupling between subject and observer)

VIII Typical application in JDK

In Java There are many observer patterns under the AWT package. Let's take a look at the simple UML class diagram first
Topic role: component class provided by java (take Button as an example)
Observer role: event listener provided by java (various listeners)
Event roles: mouse events, keyboard events, and so on

Let's take a look at a small demo
Add a button in the window, add mouse and keyboard related events to the button, and print corresponding statements on the console when clicking the button or pressing the keyboard

public class MainFrame extends JFrame {
    public MainFrame() throws HeadlessException {
        //Define a specific topic
        Button button = new Button("click");

        //Add an observer to the topic (mouse listening)
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //MouseEvent is a specific event
                System.out.println("The button is clicked");
            }
        });

        //Add an observer to the topic (keyboard monitor)
        button.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                //KeyEvent is a specific event
                System.out.println("Press" + e.getKeyChar());
            }
        });

        add(button);
        setSize(100,100);
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new MainFrame();
    }
}

The KeyAdapter and MouseAdapter here use Adapter mode