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

本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/

 

观察者模式简述

观察者模式的使用非常广泛,常用于建立起一种多对一的关系,该模式一定会包含两个角色,观察者和被观察的对象,当被观察的对象发生变化的时候观察者会接受到相应的通知。

 

观察者模式的定义与基本结构

定义:定义一个一对多的依赖关系,当被多个对象依赖的那个对象发生改变的时候,所有依赖它的对象都会得到相应的通知并进行状态的更新。

 

让我们来看一张来自《Head First》的结构图。

Subject:被观察对象的接口,只要实现了这个接口,任何类都可以成为被观察的对象,这种面向接口的编程方式让类之间的耦合度降低。

Observer:观察者对象的接口,只要实现了这个接口,任何类都可以成为被观察的对象,这种面向接口的编程方式让类之间的耦合度降低。

ConcreteSubject:实现了Subject接口的具体实例。

ConcreteObserver:实现了Observer接口的具体实例。

 

注:一对多指的是一个Subject可以被很多observer观察。

 

一个简单的实例(java)

从观察者更新信息的方式上,可以将观察者模式的实现分成两类,一类是每次Subject更新了信息,Observer都会收到更新的信息(被称为push方式),另一类是每次Subject更新的时候,只通知Observer信息被更新了,但是需要Observer在需要的时候自己来取新的信息(被称为pull方式)。

 

我们只给出push方式完整的代码,然后文字叙述pull与push实现的区别,感兴趣的朋友可以自己试着实现pull版本。

 

让我们来考虑这样一个例子,只要我们定了一份新的杂志,每当这份杂志有新的版本的时候,在push方式下,这本杂志就会被送到每一个订阅者的家里,这里发行商就是ConcreteSubject类,顾客是ConcreteObserver类,实现如下。

Subject接口

1 public interface Subject {
2     void addObserver(Observer o);
3     void deleteObserver(Observer o);
4     void notifyObserver();
5 }

 

Observer接口

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

 

Publisher类,继承了Subject接口

 1 public class Publisher implements Subject {
 2     private ArrayList<Observer> customer;
 3     private String magazine;
 4     public Publisher(){
 5         customer=new ArrayList<Observer>();
 6         magazine="";
 7     }
 8     @Override
 9     public void addObserver(Observer o) {
10         customer.add(o);
11         System.out.println("新顾客加入");
12     }
13 
14     @Override
15     public void deleteObserver(Observer o) {
16         customer.remove(o);
17         System.out.println("老顾客退出");
18     }
19     @Override
20     public void notifyObserver() {
21         for(Observer o:customer){
22             o.update(magazine);
23         }
24     }
25     public void publishNewMagazine(String magazine){
26         this.magazine=magazine;
27         notifyObserver();
28     }
29 }

 

Customer类,继承了Observer接口

 1 public class Customer implements Observer {
 2     String name;
 3     public Customer(String name){
 4         this.name=name;
 5     }
 6     @Override
 7     public void update(String magazine) {
 8         System.out.println(name+" 拿到了新的杂志 "+magazine)    ;
 9     }
10 }

 

测试程序如下

 1 public class Test {
 2     public static void main(String[] args) {
 3         Publisher publisher=new Publisher();
 4         Customer customer1=new Customer("叶良辰");
 5         Customer customer2=new Customer("龙傲天");
 6         publisher.addObserver(customer1);
 7         publisher.addObserver(customer2);
 8         publisher.publishNewMagazine("装B指南");
 9         publisher.deleteObserver(customer1);
10         publisher.publishNewMagazine("上天秘籍");
11     }
12 }

 

输出如下

 

pull与push主要的区别

1,pull式需要Observer自己去取数据,所以Subject要提供相应的get方法

2,pull式虽然不用主动push数据,但是仍然要在每次更新时告知Observer数据已经更新,所以每一个Observer需要设立一个flag表示自己数据的新旧。

3,object需要判断哪些Observer有权限来取得自己的数据。

pull方式在那种只有最新信息有价值且Subject更新太快而不适合用push的情况下使用比较好,比如手机上接受天气预报信息之类的

 

Java的built-in Observer Pattern

因为观察者模式实在是太常用了,以至于java给我提供了相应的工具直接构建Observer模式,java提供了一个Observable类(作用相当于我们刚刚写的Object,但是这个是类不是接口),和Observer接口,我们只要继承这些类和接口就能直接应用观察者模式了

它们的位置

import java.util.Observable;
import java.util.Observer;

 

Observer类里有以下成员方法

addObserver(Observer o);//添加observer
clearChanged();//重置更新标志,hasChanged()的返回值将为false
countObservers();//返回observer的数量
deleteObserver(Observer o);//删除一个特定的observer
deleteObservers();//删除所有observer
hasChanged();//测试object的内容距上一次通知后有没有更新
notifyObservers();//如果object内容有更新,调用这个方法会通知所有observer,之后会调用clearChange()方法,这个方法是为pull式实现准备的。
notifyObservers(Object arg);//如果object内容有更新,调用这个方法会将参数中arg的更新推送给所有observer,之后会调用clearChange()方法,这个方法是为push式实现准备的
setChanged();//标明object已经更新

 

Observer接口里面只有一个update方法,声明如下

 public void update(Observable o, Object arg); 

第一个参数是被观察的对象,第二个是任何我们想更新给observer的对象,这个对象来自notifyObservers的参数,如果缺失这个参数,表示我们的observer需要自己来拿数据(即pull式实现),如果有这个对象,则属于push式实现。

运用这个java提供的观察者模式的实现我们只需要做两件事。

1,决定使用pull式实现还是push式实现。

2,根据我们的决定实现update方法,如果我们用pull式实现,我们最好在Subject类里提供相应的get方法。

 

这里给出一个示例,还是上面的例子,仍然是push式,这次我们不用写object与observer接口了。

Customer类

 1 public class Customer implements Observer {
 2     String name;
 3     boolean newManagzine=false;
 4     public Customer(String name){
 5         this.name=name;
 6     }
 7     @Override
 8     public void update(Observable o, Object arg) {
 9             System.out.println(name+" 拿到了新的杂志 "+arg);
10     }
11 }

 

Publisher类

 1 import java.util.Observable;
 2 public class Publisher extends Observable {
 3     private String magazine;
 4     public Publisher(){
 5         super();
 6         magazine="";
 7     }
 8     public void publishNewMagazine(String magazine){
 9         setChanged();
10         this.magazine=magazine;
11         notifyObservers(magazine);
12     }
13 }

 

test代码完全不用改,输出如下

 

java给的观察者模式的实现方法其实还有有蛮多的局限性的,比如observable是个类而不是接口,而java是不支持多继承的,所以有了局限性,所以大多数情况下,我们还是自己实现会比较方便。

 

观察者模式到此结束♪(^∇^*)

 

参考资料:

1,《Head First 设计模式》

2,在线java API http://tool.oschina.net/apidocs/apidoc?api=jdk_7u4

 

posted @ 2016-05-11 14:17  呆代待殆  阅读(641)  评论(0编辑  收藏  举报