设计模式-观察者模式(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