观察者模式实力分析

一般地,面向对象分析与设计中存在三种事件处理的机制,除了普通的函数调用外,常常用到回调函数,而J2EE中还提供了一种基于监听方式的事件处理机制,请查阅资料,对Action以及ActionListener的机制进行分析,完成一个分析实例。

首先了解观察者模式

观察者模式 (Observer Pattern)

真实世界中的观察者

观察者模式又称发布订阅模式,例如RSS(微信推送的爸爸)订阅,某博客(被观察者)的博主在更新博文后,订阅者的阅读器(观察者)上就会自动能够收到更新。这种发布-订阅的套路我们称作观察者模式。

观察者模式

(Gang Of Four)对观察者模式的描述:

  • 意图

    定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

  • 别名

    依赖(Dependents),发布-订阅(Publish-Subscribe)

  • 动机

    将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了他们的可重用性。

  • 参与者

    • subject(目标)

      目标知道他的观察者。可以有任意多个观察者观察同一目标。

      提供注册和删除观察者对象接口。

    • Observer(观察者)

      为那些咋目标发生改变时需获得通知的对象定义一个更新接口。

    • ConcreteSubject(具体目标)

      将有关状态存入各ConcreteObserver对象。

      当他的状态发生改变时,向他的各个观察者发出通知。

    • ConcreteObserver(具体观察者)

      维护一个指向ConcreteSubject对象的引用。

      存储有关状态,这些状态应与目标的状态保持一致。

      实现Observer的更新接口以使自身状态与目标的状态保持一致。

可以发现观察者模式常常应用于:

  • 两个对象具有依赖关系。
  • 一个对象更改时需要同时更改其他对象。

相比于普通的函数调用以及回调函数,观察者模式的使用能够做到低成本维持对象间一致性,大大降低了对象间的耦合关系程度,同时可以达到广播的效果,这是前二者做不到的。观察者模式的使用大大提高了代码的可重用性**。

而J2EE中的Action和ActionListener正是观察者模式的一个鲜活的例子。

J2EE中的Action&ActionListener

Action&ActionListener 可以很好地应用于MVC范式用来降低model和view的耦合程度。

找到一个很好的例子,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class Frame extends JFrame {

ActionListener observer1 = new Observer("First Observer");
ActionListener observer2 = new Observer("Second Observer");
ActionListener observer3 = new Observer("Third Observer");

public Frame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
init();
}

private void init(){
addChangingTextField();
pack();
setVisible(true);
}

private void addChangingTextField(){
//Observable class TextField. each time
//An action or event occurs the observers will be updated
//Almost all the Swing classes has this kind of behavior
JTextField dataTextField = new JTextField();

// Observer registering to the observable class.
dataTextField.addActionListener(observer1);
dataTextField.addActionListener(observer2);
dataTextField.addActionListener(observer3);

add(dataTextField);
}

public static void main(String [] args){
Frame frame = new Frame();
}
}

class Observer implements ActionListener{

private String name;
private String message;

public Observer (String s){
name = s;
}

public void actionPerformed(ActionEvent e) {
JTextField textField = (JTextField) e.getSource();
message = textField.getText();
JOptionPane.showMessageDialog(null,
name + " has been confirmed about the change, Thanks!! "
+ " The Message was: " + message);
}
}

分析

两个类分别担任了Action/ActionListener的角色,frame.dataTextFieldaddChangingTextField方法中绑定了三个监听器(observer1, observer2, observer3),在frame中文本框被编辑后(状态改变),触发Observer中actionPerformed方法,显示相应文本。

在这个例子中,frame.dataTextField作为ConcreteSubjectobserver1, observer2, observer3作为ConcreteObserver。而他们所实现的定义了Action/ActionListener方法的接口,则是相应的SubjectObserver

在绑定观察者后目标并不关注观察者具体的行为,而只是在自身状态发生改变时通知观察者,由观察者自身决定做什么动作,因此这种方法就很nice,比显式调用函数或者执行回调函数的方式触发动作不知道高到哪里去了,值得学习一个。