观察者模式–快速理解观察者模式
原理解释
例子: 当我们在电脑键盘上打字时,敲下”A”,屏幕上会立刻出现一个 “A”。(当然实际上还会有很多处理流程,此处我们简化忽略)
这就可以理解成一个观察者模式,其中:屏幕是一个观察者,键盘是被观察者,数据线则是他们之间的关联(订阅),屏幕时刻在观察着键盘,键盘敲了什么,屏幕就立刻显示什么。
订阅 是观察者和被观察者联系的桥梁,上面的例子中–屏幕到键盘这里做了一个订阅动作(数据线),告诉键盘,如果有任何输入,立马通过数据线告知我。
下面我们通过Java代码实现上面的例子并进行分析:
import java.util.LinkedList;
import java.util.List;
/**
* 观察者接口
*
* @author stormbaron
*/
interface Oberver {
// 观察到情况后的动作(回调方法)
public void work();
}
/**
* 被观察者接口
*
* @author stormbaron
*/
interface Oberved {
// 订阅
public void subscribe(Oberver oberver);
// 通知所有订阅的观察者
public void notifyOberver();
}
/**
* 键盘类(被观察者)
*
* @author stormbaron
*
*/
class KeyBoard implements Oberved {
// 观察者集合
List<Oberver> Obervers = new LinkedList<Oberver>();
// 订阅
public void subscribe(Oberver oberver) {
Obervers.add(oberver);
}
// 通知观察者
public void notifyOberver() {
if (Obervers != null) {
for (Oberver mOberver : Obervers) {
mOberver.work();
}
}
}
}
/**
* 屏幕类(观察者)
*
* @author stormbaron
*
*/
class Screen implements Oberver {
public void work() {
System.out.println(" I am " + this.toString() + ",I get a Message that KeyBoard imput ");
}
}
public class ObserverTest {
public static void main(String[] args) {
Oberved myKeyBoad = new KeyBoard();
Oberver myScreen1 = new Screen();
Oberver myScreen2 = new Screen();
Oberver myScreen3 = new Screen();
// 订阅
myKeyBoad.subscribe(myScreen1);
myKeyBoad.subscribe(myScreen2);
myKeyBoad.subscribe(myScreen3);
// 通知
myKeyBoad.notifyOberver();
}
}
上面的代码实现了多个屏幕观察一个键盘,并在键盘发出一个通知后所有订阅的屏幕同时反应。
实际项目使用场景
实际需求:
一个Android界面同时显示3个图表,图表数据来自网络,每隔30秒更新一次数据。
思路
View层: 3个Fragment
Control层:Activity
Model层:一个DataModel + HttpUtil 在DataModel提供3个公开的返回特定格式数据方法
此处进行简单MVC模式的分层操作,
此时,我们实际上有许多种方法可以达成目标,例如
(1)在DataModel中利用定时任务,每30秒进行一次网络数据请求,然后更新保存在DataModel中的封装数据(提供给View层)
在Fragment中利用定时任务,定时刷新图表。
(2)利用观察者模式,在DataModel中利用定时任务,每30秒进行一次网络数据请求,然后更新保存在DataModel中的封装数据(提供给View层),同时向所有有订阅关系的Fragment发送通知,使所有Fragment及时刷新图表。
事实上上面两种方式,主要是在View层的数据刷新上有所区别,一种是自己主动不断定时去判断和刷新,另外一种则是被动通知刷新。
从实现角度讲,第一种更简单容易想到和实现,View层和Model层也不需要有任何耦合,但是需要额外运行多个子线程,增加了开销,同时也造成页面数据刷新的不及时。
而第二种方法,利用观察者模式,Fragment实现观察者接口,DataModel实现被观察者接口,将3个Fragment全部订阅到DataModel中,每次DataModel完成数据更新后调用notifyOberver(),通知所有观察者(Fragment)进行数据更新。降低了内存开销,并且及时地进行数据刷新。