什么是观察者模式
观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。
对于观察者模式而言,肯定有观察者和被观察者之分。比如在一个目录下建立一个文件,这时系统会通知目录管理器增加目录,并通知磁盘减少空间,在这里,文件就是观察者,目录管理器和磁盘就是被观察者。
观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:
其中,Subject类是主题,它把所有对观察者对象的引用文件存在了一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者对象;Observer类是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;ConcreteSubject类是具体主题,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知;ConcreteObserver是具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。
主题Subject
首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用CopyOnWriteArrayList是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。
public class Subject {
//观察者数组
private CopyOnWriteArrayList<Observer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
//增加一个观察者
public void addObserver(Observer observer) {
this.copyOnWriteArrayList.add(observer);
}
//删除一个观察者
public void deleteObserver(Observer observer) {
this.copyOnWriteArrayList.remove(observer);
}
//通知所有观察者
public void notifyObserver() {
copyOnWriteArrayList.forEach(item -> {
item.update();
});
}
}
抽象观察者
观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。
public interface Observer {
//更新
void update();
}
具体主题
继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种
public class ConcreteSubject extends Subject {
//具体业务
public void doSomething(){
//...
super.notifyObserver();
}
}
具体观察者
public class ConcreteObserver implements Observer{
@Override
public void update() {
System.out.println("收到消息,进行处理");
}
}
//客户端
public class Client {
public static void main(String[] args) {
//创建一个主题
ConcreteSubject subject = new ConcreteSubject();
//定义一个观察者
Observer observer=new ConcreteObserver();
//观察
subject.addObserver(observer);
subject.doSomething();
}
}
观察者模式的实现
下面举一个具体实例,假设上班时间有一部分同事在看股票,一部分同事在看NBA,这时老板回来了,前台通知了部分同事老板回来了,这些同事及时关闭了网页没被发现,而没被通知到的同事被抓了个现行,被老板亲自“通知”关闭网页,UML图如下:
image.png
通知者接口
public interface SubjectDemo {
//增加
void attach(ObserverDemo observerDemo);
//删除
void detach(ObserverDemo observerDemo);
//通知
void notifyObservers();
//状态
void setAction(String action);
String getAction();
}
观察者接口
public abstract class ObserverDemo {
protected String name;
protected SubjectDemo subjectDemo;
public ObserverDemo(String name, SubjectDemo subjectDemo) {
this.name = name;
this.subjectDemo = subjectDemo;
}
public abstract void update();
}
具体通知者
前台Secretary和老板Boss作为具体通知者,实现Subject接口。这里只给出Secretary类的代码,Boss类与之类似。
public class Secretary implements SubjectDemo {
//同事列表
private List<ObserverDemo> observerDemos = new CopyOnWriteArrayList<>();
private String action;
@Override
public void attach(ObserverDemo observerDemo) {
observerDemos.add(observerDemo);
}
@Override
public void detach(ObserverDemo observerDemo) {
observerDemos.remove(observerDemo);
}
@Override
public void notifyObservers() {
observerDemos.forEach(item -> {
item.update();
});
}
@Override
public void setAction(String action) {
this.action = action;
}
@Override
public String getAction() {
return action;
}
}
具体观察者
public class StockObserver extends ObserverDemo {
public StockObserver(String name, SubjectDemo subjectDemo) {
super(name, subjectDemo);
}
@Override
public void update() {
System.out.println(subjectDemo.getAction()+"\n"+name+"关闭股票行情,继续工作");
}
}
public class NBAObserver extends ObserverDemo {
public NBAObserver(String action, SubjectDemo subjectDemo) {
super(action, subjectDemo);
}
@Override
public void update () {
System.out.println(subjectDemo.getAction() + "\n" + name + "关闭直播,继续工作");
}
}
前台作为通知者进行通知
前台作为通知者,通知观察者。这里添加adam和tom到通知列表,并从通知列表中删除了adam,测试没在通知列表中的对象不会收到通知。
public class TestDemo {
public static void main(String[] args) {
//前台为通知者
Secretary secretary = new Secretary();
StockObserver observer = new StockObserver("adam", secretary);
NBAObserver observer1 = new NBAObserver("tom", secretary);
//前台通知
secretary.attach(observer);
secretary.attach(observer1);
//adam没有被前台通知到,所以被老板抓个现行
secretary.detach(observer);
//老板回来了
secretary.setAction("小心!Boss回来了!");
//发通知
secretary.notifyObservers();
}
}
网友评论