简述
简单来说,观察者模式可以这样理解:定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新。
情景模式
上面描述过于官方,不容易理解,所以我们可以放到某种情景中去就容易理解了。
比如:在简书上有某位作者的文章我很喜欢,但是呢,我不知道他什么时候会更新文章,我也不会每隔一段时间去刷新一下,看看他有没有发布新的文章,这样太累了。所以我可以选择关注这位作者,当他有新的文章发布时,我就会收到一个推送消息,告诉我新文章上线了,可以去欣赏一下了;如果哪天我不想接收他的新文章上线的推送,那我对他取消关注就可以了。
实例
1. 关键元素
上述的情景中,我们可以发现三个比较重要的环节:关注、推送、取消关注;
这个和观察者模式也是相对应的:注册(订阅)、反注册(取消订阅)、通知改变数据。
2. 代码实例
(1). 定义被观察者(非接口模式)
/*
* 被观察者
* 一般被观察者被定义为接口,然后其他类去继承并实现其中的方法,
* 这里换种方式,直接在被观察者中实现方法
*/
public class Observable<T> {
//观察者的集合
private List<Observer<T>> observers = new ArrayList<Observer<T>>();
//注册
public void register(Observer<T> observer) {
if (observers != null && !observers.contains(observer)) {
observers.add(observer);
}
}
//取消注册
public void unregister(Observer<T> observer) {
if (observers != null) {
observers.remove(observer);
}
}
//通知所有观察者数据发生了改变
public void notifyAllObserver(T data) {
for (Observer<T> observer : observers) {
observer.bookUpdate(observer, data);
}
}
//通知单个观察者数据发生了改变
public void notifyObserver(Observer<T> observer, T data) {
observer.bookUpdate(observer, data);
}
}
(2). 定义观察者(接口模式)
/*
* 观察者,数据更新的接口
*/
public interface Observer<T> {
void bookUpdate(Observer<T> observer,T data);
}
(3). 实体类(如果被观察者是接口形式的,可以继承被观察者,实现里面的方法)
/*
* 实体类,可以继承接口形式的被观察者Observeable
*/
public class Books {
private String bookName;
private String bookPrice;
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getBookPrice() {
return bookPrice;
}
public void setBookPrice(String bookPrice) {
this.bookPrice = bookPrice;
}
@Override
public String toString() {
return "welcome! The book "+bookName+" is update, price is $"+bookPrice;
}
}
(4). 具体实现(只包含主要代码)
/*
* 这个方法主要是初始化数据,
*/
private void initData() {
//实例化一个被观察者
observable = new Observable<Books>();
//实例化观察者1
observer1 = new Observer<Books>() {
@Override
public void bookUpdate(Observer<Books> observer, Books data) {
System.out.println("观察者1 :" + data.toString());
}
};
//实例化观察者2
observer2 = new Observer<Books>() {
@Override
public void bookUpdate(Observer<Books> observer, Books data) {
System.out.println("观察者2 :" + data.toString());
}
};
//实体类数据赋值
books1 = new Books();
books1.setBookName("冬天的席丽拓");
books1.setBookPrice("122");
books2 = new Books();
books2.setBookName("空的.上午");
books2.setBookPrice("24");
books3 = new Books();
books3.setBookName("单独的更新");
books3.setBookPrice("85");
}
/*
* 点击时间中实现注册与反注册,并通知数据改变
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.register:
//注册
observable.register(observer1);
observable.register(observer2);
//通知数据改变
observable.notifyAllObserver(books1);
observable.notifyAllObserver(books2);
//这个是单独通知观察者1,数据改变了
observable.notifyObserver(observer1, books3);
break;
case R.id.unregister:
//取消观察者1的注册,保留观察者2的注册,发动通知后,只有观察者2可以收到消息
observable.unregister(observer1);
observable.notifyAllObserver(books1);
observable.notifyAllObserver(books2);
break;
default:
break;
}
}
(5). 通知结果
1.第一次注册
2.取消注册
3.再一次注册
观察结果:
(1) 第一次注册并发送通知,两个观察者都收到了消息,并且观察者1一共有3条消息,观察者2两条消息。
(2) 取消观察者1的注册并发送通知,只有观察者2收到了两条消息
(3) 再次注册并发送通知,两个观察者都收到了消息,并且观察者1一共有3条消息,观察者2两条消息,但是请注意红色框中的观察者的顺序有所改变。
总结
观察者模式总结过来最大的是抓住三个要素:注册(订阅)、反注册(取消订阅)、通知改变数据。
实际的开发中遇到的情况相比这个例子要复杂很多,但是只要理解了观察者模式的这种实现方式与思想,很多复杂的事情就变得简单了。(以上纯属个人理解,如有错误的地方,烦请指正,感谢!)