Observer观察者模式定义
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。这种模式最常用在我们熟悉的事件驱动模型里面,像VC、JAVA的swing,Android界面里面的事件响应,就是基于观察者模式来实现的。
Observer观察者模式的组成
观察者模式的类图如下:
可以看出,在这个观察者模式的实现里有下面这些角色:
抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
抽象主题(Subject)角色:主题角色把所有对观察考对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
具体主题(ConcreteSubject)角色:将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色通常用一个具体子类实现。
具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
Observer观察者模式模拟-按钮响应事件
下面我们写一个例子来模拟观察者模式的实现,大家就能清楚的看出观察者模式的基本原理。例子是button按钮的响应事件,在VC、Swing或者Android系统的界面设计中,每种控件的响应模式就是用的观察者模式。
新建一个Test.java的文件,由于该例子比较简单,所有的类我们都放在这个文件中。然后是Button类的实现(Button类相当于上图左侧的主题类和抽象主题,也就是被观察对象。Button类比较简单就未再写出抽象主题):
private List<ActionListener> actionListeners = new ArrayList<ActionListener>(); /*被观察对象中维护一个观察者链表,每次有新的观察者加入时调用addActionListener()即可增加到链表中 */
public void buttonPressed() { /* 按钮按下事件,激发观察者调用行为actionPerformed(),同时将发生的事件ActionEvent()传递给观察者*/
for(int i=0; i<actionListeners.size();i++) {
ActionListener l = actionListeners.get(i);
ActionEvent e = new ActionEvent(System.currentTimeMillis()); /* 此刻事件类携带的就是发生按下按钮事件时的系统时间 */
l.actionPerformed(e);
}
}
interface ActionListener {
public void actionPerformed(ActionEvent e);
}
具体观察者的实现,该处使用了三种观察者,每种在收到按钮事件发生时简单的打印一个字符串模拟事件的响应:
class myActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被按下了!! 时间是" + e.getWhen());
}
}
class myActionListener2 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("你点了确认键!!");
}
}
class myActionListener3 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("将要进入XX网站!!");
}
}
最后是事件函数的定义,在被观察对象Button的按钮被点击时,触发ActionEvent事件传递给观察者,此时事件类就是获取系统的事件,传递给观察者。这样观察者可以针对传递过来的事件作出不同的响应:
class ActionEvent {
private long when;
public ActionEvent(long when) {
super();
this.when = when;
}
public String getWhen() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年-MM月dd日-HH时mm分ss秒");
Date date = new Date(when);
return formatter.format(date);
}
}
测试下该程序,写一个main函数:
public class Test {
public static void main(String[] args) {
Button b = new Button(); /* 建立一个被观察者 */
b.addActionListener(new myActionListener());
b.addActionListener(new myActionListener2());
b.addActionListener(new myActionListener3()); /* 为该被观察者增加三个观察者对象 */
b.buttonPressed(); /* 按钮按下,事件发生 */
}
}
运行该程序,可以发现执行结果是三个观察者都观察到了按钮被按下的事件,每个观察者作出了不同的响应,其中第一个观察者获取到了事件类,也就是事件发生的系统时间:
Android 应用开发中的观察者模式
在我们做Android应用的时候,会大量使用观察者模式,因为Framework层里面的事件驱动都是基于观察者模式实现的。另外在Framework层里面的各种服务在数据变更的时候,也是通过观察者模式实现上层数据更新。
Android里面最典型的观察者就是我们使用的各种控件监听者。例如下面对某个按钮的监听:
<span style="font-size:12px;">Button baiduclickButton = (Button)findViewById(R.id.button1);
//注册观察者baiduclickButton.setOnClickListener(new OnClickListener(){
//观察者实现
@Override
public void onClick(View arg0) {
Log.d("Mythou_Log", "Click the button ");
}
});</span>
每当我们的目标按钮对象被点击,状态发生变化的时候,就会通过回调注册的OnClickListener观察者的onClick方法会来通知观察者,Button状态发生变化。这里的onClick相当于前面例子里面的update方法。下面是Android源码里面对OnClickListener的定义,跟我们前面定义一个观察者接口类似。
<span style="font-size:12px;">public interface OnClickListener {
/**
* Called when a view has been clicked.
** @param v The view that was clicked.
*/
void onClick(View v);
}</span>