设计模式之观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
一、介绍
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作
关键字
Observable
即被观察者,也可以被叫做主题(Subject)是被观察的对象。通常有注册方法(register),取消注册方法(remove)和通知方法(notify)。
Observer
即观察者,可以接收到主题的更新。当对某个主题感兴趣的时候需要注册自己,在不需要接收更新时进行注销操作。
二、代码示例
举一个生活中的例子:比如用户从报社订阅报纸,报社和用户之间是一对多依赖,用户可以在报社订阅(register)报纸,报社可以把最新的报纸发给用户(notify),用户自动收到更新。在用户不需要的时候还可以取消注册(remove)。
- 首先我们抽象出一个报纸实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NewsModel {
String title;
String content;
}
- 定义一个被观察者(Subject)和观察者接口,
/**
* 被观察者接口定义
*/
public interface MyObserverable {
void register(MyObserver myObserver);
void remove(MyObserver myObserver);
void send(NewsModel model);
}
/**
* 观察者接口定义
*/
public interface MyObserver {
void receive(NewsModel model);
}
- 用户抽象
/**
* 对于用户的抽象
*/
public class User implements MyObserver {
private String mName;
public User(String name) {
mName = name;
}
@Override
public void receive(NewsModel model) {
System.out.println(mName + " receive news:" + model.getTitle() + " " + model.getContent());
}
}
- 报社抽象
/**
* 对于报社的抽象,实现了被观察者接口,每隔5s发送一次报纸
*/
public class NewsProvider implements MyObserverable {
private static final long DELAY = 2 * 1000;
private List<MyObserver> mObservers; //我们用一个List来维护所有的观察者对象
public NewsProvider() {
mObservers = new ArrayList<>();
generateNews();
}
/**
* 模拟产生新闻,每隔5s发送一次
*/
private void generateNews() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int titleCount = 1;
int contentCount = 1;
@Override
public void run() {
send(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
}
}, DELAY, 5000);
}
@Override
public void register(MyObserver myObserver) {
if (myObserver == null)
return;
synchronized (this) {
if (!mObservers.contains(myObserver))
mObservers.add(myObserver);
}
}
@Override
public synchronized void remove(MyObserver myObserver) {
mObservers.remove(myObserver);
}
@Override
public void send(NewsModel model) {
for (MyObserver observer : mObservers) {
observer.receive(model);
}
}
}
- 测试类
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
NewsProvider provider = new NewsProvider();
User user;
for (int i = 0; i < 10; i++) {
user = new User("user:"+i);
provider.register(user);
}
}
}
运行测试类,就能看到每隔5秒,观察者收到了报纸。(其实就是观察者触发了某个receive方法)
三、java自带的观察者api
public interface Observer {
void update(Observable o, Object arg);
}
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
源码比较简单,这个类是从JDK1.0就开始出现,
private Vector<Observer> obs;
这句代码用来存放观察者对象的,可以看到使用的还是Vector类。
Observable提供的changed属性
private boolean changed = false;
通过设置这个变量来确定是否通知观察者。
你所看得到的天才不过是在你看不到的时候还在努力罢了!