观察者模式是面向对象编程中较为常见的一种设计模式,观察者模式又称为订阅发布模式,可能大家对观察者模式从字面上可以理解,但是对代码层面上不太清楚如何实现,通过本文学习,相信你会对观察者有一个更清晰的了解。
定义
观察者模式:定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。
从上面的定义描述中,我们可以了解到观察者模式有两个重点:观察者、被观察者。我们从生活中的例子来理解下。我们去报社订阅报纸,报社与用户之间就是一对多依赖,用户可以在报社订阅(register)报纸,报社可以把最新的报纸发到用户手上(notify),用户就会收到最新的报纸。用户不再需要的时候可以取消订阅(remove)。
从现在热门Library有EventBus,RxJava的实现都是基于观察者模式思想,到时有人问起时,你会从使用层面到源码层面都能说清他们的时候。另外Android的点击监听事件OnClickListener都是使用了观察者模式。
从字面意思上理解完之后,我们看一下UML类图,从类图方面来理解观察者模式。
UML类图
我们分析一下上图:
Observerable:被观察者接口,规定了三个方法,分别是registerObserver():表示将观察者注册到被观察者中,即“订阅”;removeObserver():表示将观察者从被观察者中移除,即“取消订阅”;notifyObservers()当被观察者的属性发生变化时候,这个方法将被调用,通知所有已经订阅注册的观察者。
ConcreteObserverable:被观察者,实现Observerable接口,在对上面的方法实现,同时有一个List集合,用保存注册的观察者,等通知观察者的时候遍历该集合。
Observer:观察者接口,定义update()方法,当被观察者通知观察者时候,观察者的update()方法将被回调。
ConcreteObserver:观察者,实现了update()方法。
从UML类图中,我们了解了观察者模式的实现过程,接下来我们从代码来进一步理解。
代码实现
被观察者接口:
interface Observerable {
void registerObserverable(Observer o);
void removeObserverable(Observer o);
void notifyObserverable();
}
观察者接口:
interface Observer {
void update(NewsPaper newspager);
}
新建报社类,实现被观察者接口:
public class Company implements Observerable {
private List<Observer> observers;
private NewsPaper mNewsPaper;
public Company() {
observers = new ArrayList<>();
}
@Override
public void registerObserverable(Observer o) {
// TODO Auto-generated method stub
if (null == o)
return;
observers.add(o);
}
@Override
public void removeObserverable(Observer o) {
// TODO Auto-generated method stub
if (null == o || observers.size() <= 0)
return;
observers.remove(o);
}
@Override
public void notifyObserverable() {
// TODO Auto-generated method stub
for (int i = 0; i < observers.size(); i++) {
Observer observer = observers.get(i);
observer.update(mNewsPaper);
}
}
public void setNewsPaperBean(NewsPaper newsPaper) {
this.mNewsPaper = newsPaper;
notifyObserverable();
}
}
新建用户类,实现观察者接口:
public class User implements Observer {
private String mUserId;
private NewsPaper mNewsPager;
public User(String id) {
mUserId = id;
}
@Override
public void update(NewsPaper newspager) {
// TODO Auto-generated method stub
mNewsPager = newspager;
buy();
}
private void buy() {
System.out.println("用户" + mUserId + "获得报纸" + mNewsPager.getMessage());
}
}
观察者类与被观察者类我们都准备好了,接下来我们看一下客户端如何实现:
public class JavaDemo {
public static void main(String[] args) {
//创建被观察者实例
Company company = new Company();
//创建三个观察者用户实例
Observer customerA = new User("A");
Observer customerB = new User("B");
Observer customerC = new User("C");
//只有A、B用户进行了注册订阅
company.registerObserverable(customerA);
company.registerObserverable(customerB);
//被观察者报社公司更新了新的报纸,通过订阅了的用户观察者
company.setNewsPaperBean(new NewsPaper("羊城晚报"));
}
}
打印结果:
用户A获得报纸羊城晚报
用户B获得报纸羊城晚报
从上面的例子中,我们看到出,这其实就是我们平时用的接口回调吗?甲乙两个对象,乙方持有甲方对象,在一定情况下,乙方用甲对象调用甲方方法。实现了回调方法。的确非常相似,但是我们的观察者模式是一对多的依赖。通过我们这里的观察者模式的了解,我们在学习EventBus和Retrofit的时候相信会更加易入手。
Java内置观察者模式
上面的都是根据我们的需要来实现观察者模式的,然而Java中,也为我们提供了Observerable类和Observer接口。我们看一下代码是如何实现:
新建被观察者,继承Observable:
public class Company extends Observable {
private NewsPaper newsPaper;
public void setNewsPaperBean(NewsPaper newsPaper) {
this.newsPaper = newsPaper;
setChanged();
notifyObservers();
}
public NewsPaper getNewsPaper() {
return newsPaper;
}
public void setNewsPaper(NewsPaper newsPaper) {
this.newsPaper = newsPaper;
}
}
新建观察者,实现Observer:
public class User implements Observer {
private String mUserId;
private NewsPaper mNewsPager;
public User(String id) {
mUserId = id;
}
@Override
public void update(Observable o, Object arg1) {
// TODO Auto-generated method stub
if (o instanceof Company) {
Company company = (Company) o;
mNewsPager = company.getNewsPaper();
buy();
}
}
private void buy() {
System.out.println("用户" + mUserId + "获得报纸" + mNewsPager.getMessage());
}
}
客户端实现方式:
Company company = new Company();
User customerA = new User("A");
User customerB = new User("B");
User customerC = new User("C");
company.addObserver(customerA);
company.addObserver(customerB);
company.addObserver(customerC);
company.setNewsPaperBean(new NewsPaper("广州日报"));
打印结果:
用户C获得报纸广州日报
用户B获得报纸广州日报
用户A获得报纸广州日报
从结果我们可以看出,用Java内置提供的观察者模式,实现的结果与我们自己编写的结果是一致的。
相信大家从两个例子中,对观察者模式的理解已经更加清晰了。最后相信大家更加关注观察者模式的运用环境。比如我们有两个,一个对象依赖于另一个对象的变化而变化,这个时候我们可以单独将这两个对象抽象起来,抽象成接口的形式,然后就可以利用我们的观察者模式进行解耦。更更更直接的是,当一个对象发生变化时候,需要告知两个甚至多个对象时候,观察者模式就非常的适用这个场景了。