观察者模式
观察者模式定义了对象之间的一对多依赖,这样以来,当一个对象改变状态时候,它的所有依赖者都会接收到通知并且自动更新。
通常观察者模式,分为主题(Subject),观察者(Observer)。一般主要用在当一个对象发生变化的时候,需要通知许多对象的时候,发生变化的对象称为主题,而接受对象变化信息的对象则是观察者。一旦主题对象的数据库发生了变化,那么就会自动以某种方式送到观察者,观察者可以拒绝接受消息或者注册称为主题对象的一个接受消息的对象。
主题和观察者定义了一对多的关系,观察者依赖于此主题,只要主题一旦发生变化的时候,观察者就会接收到通知。
一般应用情况,许多的对象需要共同接受某一个对象变化的消息,譬如广播订阅者,譬如在java swing组件中许多组件可能会有许多个监听事件等,均用的这种思想。
1 用户自定义观察者模式:
首先要明确,两个最主要的接口,Subject,Observer
Subject主要是发送数据变化的接口,而Observer则是接受Subject对象变化的信息。
常见Subject接口:
public interface Subject { //向该主题中注册或添加新的观察者 void registerObserver(Observer obs); //从该主题中删除移调某一个观察者 void removeeObserver(Observer obs); //通知该主题下面注册的观察者 void notifyObservers(); }
Observer接口
public interface Observer { //接受主题变化传递的消息 void update(Object obj); }
当然这只是初步的最基本的自定义模型,具体的添加观察者需要再实现了Subject后,利用集合对象来实现添加或删除观察者。
一般类图如下:
举例说明:
一个信息站,不停的接受信息,而又有许多用户需要当该信息站一旦有最新数据,则能让该信息站能主动推送数据过来,此时,就构成了一对多的对象关系,信息站变化,而用户能自动的让信息站给它们发送数据。
Subject接口和Observer接口如上定义的,
定义一个信息站类InformationStation实现了Subject接口:
import java.util.ArrayList; public class InformationStation implements Subject { // 利用ArrayList来动态的增加和移除观察者 private ArrayList<Observer> observers; // 实时数据 private int data; // 表示信息是否变化 private boolean changed = false; // 用于注册观察者 @Override public void registerObserver(Observer obs) { // TODO Auto-generated method stub observers.add(obs); } // 用于观察者移除 @Override public void removeObserver(Observer obs) { // TODO Auto-generated method stub int i = observers.indexOf(obs); if (i >= 0) observers.remove(i); } // 通知观察者 @Override public void notifyObservers() { // TODO Auto-generated method stub // 当信息发生变化的时候,发送给所有观察者 if (changed) { for (int i = 0; i < observers.size(); i++) observers.get(i).update(data); } // 发送完毕后,再次设状态 changed = false; } public void setData(int newdata) { this.data = newdata; changed = true; notifyObservers(); } // 可以供观察者来拉数据 public int getData() { return data; } }
再定义一个观察者,当然观察者可以定义许多个,只要实现了Observer接口即可,为了让观察者订阅该主题,接受主题变化时候发送的数据,可以在构造器中传递一个要注册的主题对象,也可以设置一个方法来提供观察者来设置主题:ManagerObserver类
public class ManagerObserver implements Observer { // 之所以有个Subject属性是为了便于该观察者移除该主题 private Subject station; // 获取数据 private int data; // 初始化的不做注册 public ManagerObserver() { } // 初始化的时候注册该观察者的主题对象 public ManagerObserver(Subject station) { this.station = station; // 将该观察者加入该主题对象中 station.registerObserver(this); } // 供观察者添加修改主题对象 public void setSubject(Subject station) { this.station = station; // 将该观察者加入该主题对象中 station.registerObserver(this); } // 实现该方法,当主题发生变化的时候,主题就会通过该方法发送数据 // 该update在实际的情况下,最好加上一个发送主题的对象,接口中加上即可, // 这样可以判断当一个观察者注册多个主题的时候,哪些数据属于哪个主题发送的 @Override public void update(Object obj) { // TODO Auto-generated method stub System.out.println(obj.toString()); } }
基本的模型ok了,可以做个测试类进行实现了
2 Java内置的观察者模式:
Java内置有观察者模式所需要的类,
Observer接口:如同上面的一样,主要方法为
update(Observable o,Object arg);//第一个参数为主题对象,第二个为数据
Observable类:如同上面的Subject接口,只不过这里是变成类了,里面有观察者注册,移除,通知等方法,并且有默认的Vetor集合作为属性。
在实际开发的过程中,可以直接将你的主题直接实现该Observable类,其中有两个非常重要的方法,notifyObservers();这个方法可以说主要来用于让观察者来拉数据,根据需要来接受数据,而notifyObservers(Object obj);这个方法主要是主题来主动推送数据给观察者。
Java内置的观察者模式的缺点,由于Observable是一个类,那么你在实际运用的时候,则限制一定的灵活性,因为不能同时继承多个类,你也无法建立自己的实现,除非你全部重写Observable类,由于Observable在每次发送数据的时候都会坚持changed对象的状态,但是该对象是protected,意味着你只能继承它来使用,不能new一个Observable对象,从而用组合的方式来实现。
观察者模式的优点:
支持松耦合和减少依赖性。客户端不再依赖于观察器,因为通过使用主体和 Observer 接口对客户端进行了隔离。许多框架具有此优点,在这些框架中的应用程序组件可以注册为当(低级)框架事件发生时得到通知。结果,框架将调用应用程序组件,但不会依赖于它。
观察器数目可变。观察器可以在运行时注册和移除,因为主体对于观察器数目没有任何假定。