Java设计模式中的观察者模式
非凡的小笨鱼 人气:0一.介绍
观察者模式(Observer Pattern)属于行为型模式。定义了对象之间的一对多依赖,让多个观察者同时监听某一个主题对象,类似于广播机制,只需要分发广播,感兴趣的对象自动接收该广播。我们平常所说的Observer、Listener、Hook、Callback都和这个模式有关
二.场景约束
小孩(Baby)哭的时候会通知到爸爸(Dad)和妈妈(Mum),爸爸妈妈会对此采取不同的行为
三.UML类图
版本一
版本二
新增事件类将观察者与主题解耦,观察者可以根据不同的事件执行不同的操作,也可以直接对事件源进行操作
四.示意代码(版本一)
业务代码
//抽象观察者 public interface Observer { void action(); } //抽象主题 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(); } //具体主题-被观察者 class Baby extends Subject{ @Override public void notifyObserver() { System.out.println("baby cry"); observers.forEach(Observer::action); } } //具体观察者 class Dad implements Observer { @Override public void action() { System.out.println("dad feed baby"); } } //具体观察者 class Mum implements Observer { @Override public void action() { System.out.println("mum hug baby"); } }
客户端
public class Client { public static void main(String[] args) { Baby baby = new Baby(); baby.addObserver(new Mum()); baby.addObserver(new Dad()); baby.notifyObserver(); } }
五.示意代码(版本二)
//抽象观察者 public interface Observer { void action(Event event); } //抽象主题 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(); } //具体主题-被观察者 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 class Event { public abstract Object getSource(); } //具体事件 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; } } //具体观察者 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对事件源进行处理"); } } } //具体观察者 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对事件源进行处理"); } } }
客户端
public class Client { public static void main(String[] args) { Baby baby = new Baby(); baby.addObserver(new Dad()); baby.addObserver(new Mum()); baby.notifyObserver(); } }
六.观察者模式与发布订阅模式
发布订阅模式
- 发布者不会直接通知订阅者
- 发布者与订阅者完全解耦
观察者模式
- 主题要自己通知(notify)观察者
- 主题与观察者松耦合
七.优点
- 符合依赖倒置原则(观察者与主题都依赖于抽象)
- 降低耦合(主题与观察者之间的耦合关系)
八.在JDK中的典型应用
在java.awt包下有很多观察者模式的身影,先来看下简单的UML类图
主题角色:java提供的组件类(以Button为例) 观察者角色:java提供的事件监听(各种Listener) 事件角色:鼠标事件、键盘事件等等
再来看看一个小demo 在窗口中添加一个按钮,给按钮添加上鼠标与键盘的相关事件,当点击按钮或者按下键盘的时候在控制台打印相应的语句
public class MainFrame extends JFrame { public MainFrame() throws HeadlessException { //定义一个具体主题 Button button = new Button("click"); //给主题添加观察者(鼠标监听) button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { //MouseEvent就是具体事件 System.out.println("按钮被点击"); } }); //给主题添加观察者(键盘监听) button.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { //KeyEvent就是具体事件 System.out.println("按下" + e.getKeyChar()); } }); add(button); setSize(100,100); this.setLocationRelativeTo(null); this.setVisible(true); } public static void main(String[] args) { new MainFrame(); } }
这里的KeyAdapter与MouseAdapter使用的是适配器模式
加载全部内容