观察者模式-Observer

Posted Joshua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了观察者模式-Observer相关的知识,希望对你有一定的参考价值。

观察者模式很好理解,简单来说就是:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

 

1. 自己手工创建Observer模式

首先,创建观察者接口:

1 public interface Observer {
2     void update();
3 }

Publisher接口:

1 public interface Publisher {
2     void add(Observer observer);
3 
4     void delete(Observer observer);
5 
6     void notifyObservers();
7 
8     void operation();
9 }

基本功能实现(为了线程安全我们可以选择Vector):

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 
 4 public abstract class PublisherAdapter implements Publisher {
 5     private List<Observer> observers = new ArrayList<Observer>();
 6 
 7     @Override
 8     public void add(Observer observer) {
 9         observers.add(observer);
10     }
11 
12     @Override
13     public void delete(Observer observer) {
14         observers.remove(observer);
15     }
16 
17     @Override
18     public void notifyObservers() {
19         for (Observer observer : observers)
20             observer.update();
21     }
22 
23 }

实现类:

1 public class PublisherImpl extends PublisherAdapter {
2 
3     @Override
4     public void operation() {
5         System.out.println("this is operation");
6         notifyObservers();
7     }
8 
9 }

测试类:

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         Publisher impl = new PublisherImpl();
 5         impl.add(new Observer() {
 6             
 7             @Override
 8             public void update() {
 9                 System.out.println("observer 1 receive");
10             }
11         });
12         impl.add(new Observer() {
13             
14             @Override
15             public void update() {
16                 // TODO Auto-generated method stub
17                 System.out.println("observer 2 receive");
18             }
19         });
20         impl.operation();
21     }
22 
23 }

测试结果:

this is operation
observer 1 receive
observer 2 receive

 

2. 使用java.util.Observer接口

这个接口只定义了一个方法:update()。当被观察者(observable)对象的状态发生变化时,这个方法就会被调用。通过调用被观察者对象的notifyObservers()方法通知所有的观察对象。

可以定义被观察者:

1 import java.util.Observable;
2 
3 public class Publisher extends Observable {
4     public void operation() {
5         System.out.println("this is operation");
6         this.setChanged();
7         this.notifyObservers();
8     }
9 }

则测试方法为:

 1 import java.util.Observable;
 2 import java.util.Observer;
 3 
 4 public class Main {
 5 
 6     public static void main(String[] args) {
 7         Publisher publisher = new Publisher();
 8         publisher.addObserver(new Observer() {
 9 
10             @Override
11             public void update(Observable o, Object arg) {
12                 System.out.println("observer 1 receive");
13             }
14         });
15         publisher.addObserver(new Observer() {
16 
17             @Override
18             public void update(Observable o, Object arg) {
19                 System.out.println("observer 2 receive");
20             }
21         });
22         publisher.operation();
23     }
24 
25 }

当然,若要获得被观察者的信息,可以将Observable o转换为Publisher类型:

Publisher p = (Publisher)o;

 

3. 分析Observer与Observable

如前所述,Observer接口只定义了一个方法:update()。当被观察者对象的状态发生变化时,这个方法就会被调用。java.util.Observer接口定义如下:

1 package java.util;
2 
3 public interface Observer {
4     void update(Observable o, Object arg);
5 }

 

被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个非常重要:一个是setChanged(),被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化;另一个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法。

 1 package java.util;
 2 
 3 public class Observable {
 4     private boolean changed = false;
 5     private Vector obs;
 6 
 7     public Observable() {
 8         obs = new Vector();
 9     }
10 
11     public synchronized void addObserver(Observer o) {
12         if (o == null)
13             throw new NullPointerException();
14         if (!obs.contains(o)) {
15             obs.addElement(o);
16         }
17     }
18 
19     public synchronized void deleteObserver(Observer o) {
20         obs.removeElement(o);
21     }
22 
23     public void notifyObservers() {
24         notifyObservers(null);
25     }
26 
27     public void notifyObservers(Object arg) {
28         Object[] arrLocal;
29 
30         synchronized (this) {
31             if (!changed)
32                 return;
33             arrLocal = obs.toArray();
34             clearChanged();
35         }
36 
37         for (int i = arrLocal.length-1; i >= 0; i--)
38             ((Observer)arrLocal[i]).update(this, arg);
39     }
40 
41     public synchronized void deleteObservers() {
42         obs.removeAllElements();
43     }
44 
45     protected synchronized void setChanged() {
46         changed = true;
47     }
48 
49     protected synchronized void clearChanged() {
50         changed = false;
51     }
52 
53     public synchronized boolean hasChanged() {
54         return changed;
55     }
56 
57     public synchronized int countObservers() {
58         return obs.size();
59     }
60 }

 

可用如下类图表示(图片来自于网络):

一个Observable类代表一个被观察者对象。一个被观察者对象可以有多个观察者,一个观察者是一个实现Observer接口的对象。在被观察者对象发生变化时,它会调用notifyObservers方法,此方法再调用所有观察者的update()方法。

同时,发通知的顺序在这里并没有指明。Observerable类所提供的缺省实现会按照Observers对象被登记的次序通知它们(遍历Vector),当然,我们可以在子类中改变这一次序。子类还可以在单独的线程里通知观察者对象、或者在一个公用的线程里按照次序执行。

当一个可观察者对象刚刚创立时,它的观察者集合是空的。两个观察者对象在它们的equals()方法返回true时,被认为是两个相等的对象。

 

4. 观察者模式总结

来自于:http://www.cnblogs.com/forlina/archive/2011/06/23/2088121.html

优点:

  第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。 由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
  第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知

缺点:
  第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
  第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
  第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。

以上是关于观察者模式-Observer的主要内容,如果未能解决你的问题,请参考以下文章

观察者模式(Observer Pattern)

[Android&amp;Java]浅谈设计模式-代码篇:观察者模式Observer

JAVA观察者模式(observer pattern)

JDK自带的Observable和Observer实现观察者模式

设计模式之- 观察者模式(Observer Pattern)

行为类模式:观察者(Observer)