目录
一、什么是观察者模
根据观察某个对象是否发生变化而进行相应操作的模式。
换种更好理解的说法,当某个对象发生变化时通知那些都关注这个对象的人们(订阅者或观察者),这些人们得到通知,去做相应的操作。
实际生活中的监听模式----被监听者和监听者。某犯罪分子被一个或者多个警察实施监听,当犯罪分子有所行动,则警察会监听到犯罪分子的动向而采取相应的行动。
人们订阅报纸,当报纸发布新一期的时候,会发放到各个订阅了此报纸的用户手中。用户可以从新报纸中获取取新的内容。
二、观察者模式构成
本文介绍的类名和方法名都可根据自己情况自行定义,文本中定义的类名和方法都只为方便阐述
(1)Observer
观察者(订阅者,如订阅报纸的用户)。接收被观察者状态发生变化的通知。
使用时一般先抽象一个观察者;观察者抽象类需对外提供一个方法update().这个方法供给被观察者调用,被观察者状态发生变化时调用update()通知观察者。
IObserver :观察者抽象接口,提供一个方法update()。这个方法供给被观察者调用,被观察者状态发生变化时调用update()通知观察者(接口的存在很有必要下文会详细解释)。
Observer :表示具体的观察者,需要实现观察者接口。具体的业务处理写在此类中。
(2)Observable
被观察者(被订阅的东西,如报纸)。 被监听的对象,当自身状态发生变化,通过调用观察者的update()方法通知各个已经提前注册了的观察者。
使用时一般先抽象一个被观察者;被观察者抽象类对外提供一个订阅方法subscribe(),这个方法供观察者调用,进行注册,从而使观察者和被观察者联系在一起。
还可以提供一个供观察者获取被观察者最新状态或数据的方法getObservableDate()。
IObservable :表示被观察者的接口;提供一个订阅方法subscribe(),这个方法供观察者调用,进行注册,从而使观察者和被观察者联系在一起。还可以提供一个供观察者获取被观察者最新状态或数据的方法getObservableDate()。
Observable:表示具体的被观察者,需要实现被观察者接口。
当自身状态发生变化时,它会通知各个已经订阅的观察者。
IObserver:表示观察者的接口,提供接收被观察者消息的方法(接口的存在很有必要)
Observer:表示具体的观察者,需要实现观察者接口。具体的业务处理写在此类中。
三、使用
- 创建被观察者
- 创建观察者
- 关联观察者和被观察者(订阅)并执行
(1)创建被观察者:
- 先创建一个被观察者接口
package main.obsever;
/**
* @Desc 被观察者接口
* @Author lvyang
* @Date 2020-02-24
*/
public interface IObservable {
/**
* 注册观察者
*
* @param observer
*/
void subscribe(IObserver observer);
/**
* 移除观察者
*
* @param observer
*/
void unsubscribe(IObserver observer);
/**
* 获取被观察者中的数据,具体数据获取方式可以自定义
*
* @return
*/
String getObservableDate();
}
- 然后创建一个实际的被观察者并实现被观察者接口
package main.obsever;
import java.util.ArrayList;
import java.util.List;
/**
* @Desc 实际被观察者
* @Author lvyang
* @Date 2020-02-24
*/
public class Observable implements IObservable {
private String news = "我是报社的报纸1";
public Observable() {
System.out.println("创建被观察者");
}
/**
* 存放所有观察者
*/
private List<IObserver> observersList = new ArrayList();
@Override
public void subscribe(IObserver observer) {
observersList.add(observer);
System.out.println("订阅成功");
}
@Override
public void unsubscribe(IObserver observer) {
observersList.remove(observer);
System.out.println(observer.getClass().getName()+"取消订阅成功");
}
@Override
public String getObservableDate() {
return news;
}
/**
* 实际业务处理逻辑
*/
public void execute() {
//报社出了新一期报纸。
String news2 = "新一期的报纸";
news = news2;
System.out.println("新一期的报纸");
//通知各个订阅者,出新报纸了。
for (int i = 0; i < observersList.size(); i++) {
IObserver observer = observersList.get(i);
observer.update(this,i);
}
}
}
(2)创建观察者:
- 先创建一个观察者接口
package main.obsever;
/**
* @Desc
* @Author lvyang
* @Date 2020-02-24
*/
public interface IObserver {
void update(IObservable observable,int observerIndex);
}
- 然后创建一个实际的观察者并实现观察者接口
package main.obsever;
/**
* @Desc 观察者
* @Author lvyang
* @Date 2020-02-24
*/
public class Observer implements IObserver {
public Observer(String observerName) {
System.out.println("创建" + observerName);
}
@Override
public void update(IObservable observable, int observerIndex) {
String observableDate = observable.getObservableDate();
System.out.println("观察者"+observerIndex+"收到了" + observableDate);
}
}
(3)关联观察者和被观察者(订阅)并执行:
- 这里我创建了一个测试类
package main.obsever;
/**
* @Desc 观察者模式测试类
* @Author lvyang
* @Date 2020-02-25
*/
public class ObserverTest {
public static void main(String[] args) {
//第一步创建被观察者
Observable observable = new Observable();
//第二步创建观察者
Observer observer = new Observer("观察者1");
Observer observer2 = new Observer("观察者2");
//第三步订阅
observable.subscribe(observer);
observable.subscribe(observer2);
//第四步被观察者执行方法改变自己
observable.execute();
}
}
四、需要注意的地方
(1)需要注意的地方1
- Q:为什么观察者和被观察者的接口或者抽象类的存在很有必要?
- S:使用设计模式的一个很重要的目的是封装一套可复用的代码,或者说是使你开发的一套代码具有很强的可复用性。而不是说专门针对某个具体的功能写一套代码,避免遇到类似的功能后,需要重新开发一套代码来应对新的功能。
1、 IObservable被观察者接口或抽象类,此接口中提供了一个订阅方法subscribe(),发布者或者说被观察者事先不知道谁会订阅我,但是肯定知道,订阅者们都是通过IObservable接口中的subscribe()方法来实现订阅的。
2、IObserver接口中提供一个接收被观察者通知的方法update(),所有的订阅者Observer都实现了观察者接口IObserver。所以,所有观察者都得实现update()方法。
3、 被观察者Observable 只需要维护保存IObserver和IObserver中的update()方法就可以实现通知各个观察者。
4.同理,观察者们Observer也不需要知道自己订阅的是哪个具体的被观察者。但是观察者们知道这个被观察者肯定实现了被观察者接口IObservable,所以被观察者肯定持有一个获取现在状态的方法getObservableDate()。此时观察者们就可以通过此方法来获取新的状态。
某个报社事先并不知道会被哪个用户订阅。但是这个报社知道这些定报纸的人事先都是通过报社开设的专门提供订阅报纸的办公室来订阅的。并通过我们报社合作的固定的邮递员送报纸。所以当报社有新报纸出版的话,直接到订阅办公室获取各个订阅者的信息通过邮递员把新报纸送到每位订阅者手中。订阅者也提前知道要想获得新报纸必须找某某邮递员,但是不知道邮递员发的报纸的新内容是什么。
(2)需要注意的地方2
观察者的订阅顺序是否和通知的顺序一致,通知新变化时,是否有序会影响观察者中的功能。
(3)需要注意的地方3
防止循环调用,不过很少出现:被观察者发生变化通知观察者–>观察者调用被观察者中的方法,使被观察者发生变化–>被观察者发生变化又通知观察者–>这样就循环往复下去了所以一定要注意传递更新信息的方式
五、总结
(转载请注明本文链接)