一、什么是观察者模式
-
定义:属于行为模式的一种,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
-
观察者模式结构图
-
模式中的角色
抽象主题:把所有的观察者对象的引用保存到一个聚集里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者。
具体主题:将有关状态存入具体的观察者对象中。在具体主题内部状态改变时,给所有登记过的观察者发出通知。
抽象观察者:为所有的具体观察者提供一个接口,在得到主题通知时更新自己。
具体观察者:实现抽象观察者角色所需要的更新接口,以便使本身的状态和主题状态相协调。
二、为什么用观察者模式
使用场景:
-
关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合“的关系
-
事件多级触发场景
-
跨系统的消息交换场景,如消息队列,事件总线的处理机制
优点:
-
解耦合,让耦合的双方都依赖与抽象,从而使得各自的变换都不会影响到另一边的变换
缺点:
-
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且Java中消息的通知一般是顺序执行的,那么一个观察者卡顿,会影响整体的执行效率。一般会采用异步实现。
三、怎样使用观察者模式(实际应用场景)
模拟场景:
-
主题(被观察者):ChickenStore炸鸡店
-
观察者:Buyer买家
楼下新开了一家炸鸡店,由于这家店炸鸡很好吃,所以经常出现卖断货的情况。买家屡屡去买的时候都是无货可买,只有等到下一锅炸鸡出炉的时候才能买,但是一锅炸鸡出炉又需要等待很长的时间。
这样很浪费顾客的时间,为了解决让客户等待的问题,我们让每位要来买炸鸡的顾客留下联系方式,等到下一锅炸鸡要出炉的时候,通过短信/电话的方式通知买家,买家一旦接到通知,就作出响应的动作来买炸鸡。
代码实现:
1、抽象主题:Subject
package com.itszt.subject;
import com.itszt.observer.Observer;
import java.util.HashSet;
import java.util.Set;
/**
* Created by PanYangyi on 2018/5/31.
*
* 主题对象(被观察者)
*
* 抽象类
*
*/
public abstract class Subject {
//1、主题对象注册观察者对象,放到一个集合中
Set<Observer> observers = new HashSet();
public void registObserver(Observer observer){
observers.add(observer);
}
//2、数据发生变化时,通知观察者对象
public void notifyObserver(Object data){
for (Observer observer : observers) {
observer.receiveNotify(data);
}
}
//3、主题对象自己的业务方法
public abstract void work();
}
2、具体主题(炸鸡店)
package com.itszt.subject;
import com.itszt.subject.Subject;
/**
* Created by PanYangyi on 2018/5/31.
*/
public class ChickenStore extends Subject {
@Override
public void work() {
new Thread(){
int num = 0;
@Override
public void run(){
while(true) {
num++;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("炸鸡第" + num + "锅出炉了!!!");
String data = "炸鸡第" + num + "锅炸好了,赶紧马不停蹄的过来买吧!!!";
System.out.println("--------------------------------------");
//通知观察者
notifyObserver(data);
}
}
}.start();
}
}
3、抽象观察者:Observer
package com.itszt.observer;
import com.itszt.subject.Subject;
/**
* Created by PanYangyi on 2018/5/31.
*
* 观察者
*
* 抽象类
*/
public abstract class Observer {
//1、观察者需要传入主题对象,这样才能知道观察者观察的是谁。
//用构造器传参的方式
private Subject subject;
public Observer(Subject subject){
this.subject = subject;
}
//2、观察者需要接受主题对象的通知
public abstract void receiveNotify(Object data);
}
4、具体观察者(买家)
package com.itszt.observer;
import com.itszt.subject.Subject;
/**
* Created by PanYangyi on 2018/5/31.
*/
public class Buyer extends Observer {
public Buyer(Subject subject) {
super(subject);
//观察者一旦注册好,就需要将观察者注册到主题对象中
subject.registObserver(this);
}
@Override
public void receiveNotify(Object data) {
System.out.println("buyer收到了一条短消息--->"+data);
System.out.println("赶紧下楼打车去炸鸡店买炸鸡,顺道去一人民广场占座!!!");
System.out.println("--------------------------------------------");
}
}
5、测试类
package com.itszt;
import com.itszt.observer.Buyer;
import com.itszt.observer.Observer;
import com.itszt.subject.ChickenStore;
import com.itszt.subject.Subject;
/**
* Created by PanYangyi on 2018/5/31.
*/
public class Test {
public static void main(String[] args){
//实例化一个主题对象
Subject chickenStore = new ChickenStore();
//实例化有个观察者对象
Observer buyer = new Buyer(chickenStore);
//主题对象开始工作
chickenStore.work();
}
}
运行结果: