Observer is a behavioral design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes.
Observer - defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically (the definition from Head First Design Patterns).
Observer - defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically (the definition from Head First Design Patterns).
Here's a simple Java implementation of this pattern. | Also we can extend java.util.Observable class and implement java.util.Observer interface to build observers. |
SimpleKeyListener.java: | |
package observer; public class SimpleKeyListener implements KeyListener{ public void keyPressed(char key) { System.out.println("KeyListener: key pressed..." + key); } public void keyReleased(char key) { System.out.println("KeyListener: key released..." + key); } public void keyTyped(char key) { System.out.println("KeyListener: key typed..." + key); } } interface KeyListener { public void keyPressed(char key); public void keyReleased(char key); public void keyTyped(char key); } | package observer; import java.util.Observable; import java.util.Observer; public class SimpleKeyListener implements KeyListener, Observer{ public void keyPressed(char key) { System.out.println("KeyListener: key pressed..." + key); } public void keyReleased(char key) { System.out.println("KeyListener: key released..." + key); } public void keyTyped(char key) { System.out.println("KeyListener: key typed..." + key); } @Override public void update(Observable o, Object obj) { if (obj instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent) obj; switch (keyEvent.getAction()) { case KEY_PRESSED: keyPressed(keyEvent.getCharacter()); break; case KEY_RELEASED: keyReleased(keyEvent.getCharacter()); break; case KEY_TYPED: keyTyped(keyEvent.getCharacter()); break; } } } } interface KeyListener { public void keyPressed(char key); public void keyReleased(char key); public void keyTyped(char key); } enum KeyEventAction { KEY_PRESSED, KEY_RELEASED, KEY_TYPED } class KeyEvent { private KeyEventAction action; private char character; public KeyEvent(KeyEventAction action, char character) { super(); this.action = action; this.character = character; } public KeyEventAction getAction() { return action; } public char getCharacter() { return character; } } |
Component.java: | |
package observer; import java.util.HashSet; import java.util.Set; public class Component { Set<KeyListener> keyListenerList = new HashSet<KeyListener>(); public void addKeyListener(KeyListener keyListener) { keyListenerList.add(keyListener); } public void removeKeyListener(KeyListener keyListener) { keyListenerList.remove(keyListener); } public void pressKey(char key) { // Do work System.out.println("Component: pressing key..." + key); // Send keybords events for (KeyListener keyListener : keyListenerList) { keyListener.keyPressed(key); } } public void releaseKey(char key) { // Do work System.out.println("Component: releasing key..." + key); // Send keybords events for (KeyListener keyListener : keyListenerList) { keyListener.keyReleased(key); } } public void typeKey(char key) { // Do work System.out.println("Component: typing key..." + key); // Send keybords events for (KeyListener keyListener : keyListenerList) { keyListener.keyTyped(key); } } } | package observer; import java.util.Observable; public class Component extends Observable{ public void pressKey(char key) { // Do work System.out.println("Component: pressing key..." + key); // Send keybords events setChanged(); notifyObservers(new KeyEvent(KeyEventAction.KEY_PRESSED, key)); } public void releaseKey(char key) { // Do work System.out.println("Component: releasing key..." + key); // Send keybords events setChanged(); notifyObservers(new KeyEvent(KeyEventAction.KEY_RELEASED, key)); } public void typeKey(char key) { // Do work System.out.println("Component: typing key..." + key); // Send keybords events setChanged(); notifyObservers(new KeyEvent(KeyEventAction.KEY_TYPED, key)); } } |
Main.java: | |
package observer; public class Main { public static void main(String[] args) { Component component = new Component(); component.addKeyListener(new SimpleKeyListener()); component.pressKey('a'); component.releaseKey('b'); component.addKeyListener(new SimpleKeyListener()); component.pressKey('c'); component.releaseKey('d'); } } | package observer; public class Main { public static void main(String[] args) { Component component = new Component(); component.addObserver(new SimpleKeyListener()); component.pressKey('a'); component.releaseKey('b'); component.addObserver(new SimpleKeyListener()); component.pressKey('c'); component.releaseKey('d'); } } |
Output: | |
Component: pressing key...a KeyListener: key pressed...a Component: releasing key...b KeyListener: key released...b Component: pressing key...c KeyListener: key pressed...c KeyListener: key pressed...c Component: releasing key...d KeyListener: key released...d KeyListener: key released...d | Component: pressing key...a KeyListener: key pressed...a Component: releasing key...b KeyListener: key released...b Component: pressing key...c KeyListener: key pressed...c KeyListener: key pressed...c Component: releasing key...d KeyListener: key released...d KeyListener: key released...d |
Examples of using the Observer Pattern
- Observer Pattern is widely used in Swing based applications.
- Another example. Consider that you are programming a stock market application. You'd like to know when the price of a stock changes. Instead of querying the price for each stock, register your observer to a central stock broker then have him notify you every time a price changes.
- Listener pattern is used in the JVM itself quite a lot. For instance in Java Management Extensions (JMX) you can register asynchronous listeners (named notifications) which JVM will issue whenever some condition is met (like low memory).
No comments:
Post a Comment