JAVA设计模式-09-观察者模式

参考:http://blog.****.net/pengjunlee/article/details/51707104

一、什么是观察者模式
观察者(Observer)模式是行为模式之一,它的作用是当一个被观察对象的状态发生变化时,能够自动通知相关的观察者对象,自动更新观察者对象中被观察对象的状态。它提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。
二、观察者模式的典型应用
观察者(Observer)模式多被应用于以下场景:
- 侦听事件驱动程序设计中的外部事件
- 侦听/监视某个对象的状态变化
- 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者
三、观察者模式的结构
JAVA设计模式-09-观察者模式JAVA设计模式-09-观察者模式
观察者模式中的角色及其职责如下:
抽象被观察者(Subject)角色:被观察对象的抽象类,为所有具体被观察者角色提供了一个统一接口,主要包括添加、删除、通知观察者对象方法,其内包含一个用以储存所有观察者对象的容器(Collection),当被观察者的状态发生变化时,需要通知容器中所有观察者对象,并维护(添加,删除,通知)观察者对象列表。
具体被观察者(ConcreteSubject)角色:被观察者的具体实现,包含一些基本的属性状态及其他操作,当具体被观察者的状态发生变化时,会给注册的所有观察者对象发送通知,以提示观察者对象们对其内被观察对象的状态进行更新。
抽象观察者(Observer)角色:这是一个抽象角色,通常被定义为一个接口,声明所有的具体观察者需实现的方法,当收到被观察对象状态发生变化的通知时更新自己。
具体观察者(ConcreteObserver)角色:观察者的具体实现,得到通知后将对内部被观察对象的状态进行更新,并完成一些具体的业务逻辑处理。
观察者模式结构示意源代码如下:
抽象被观察者(Subject)角色
[java] view plain copy
  1. public abstract class Subject {  
  2.     //用来保存注册过的观察者  
  3.     private List<Observer> observers=new ArrayList<Observer>();  
  4.     //注册一个观察者  
  5.     public void registerObserver(Observer observer){  
  6.         this.observers.add(observer);  
  7.     }  
  8.     //删除一个观察者  
  9.     public void unregisterObserver(Observer observer){  
  10.         this.observers.remove(observer);  
  11.     }  
  12.     //通知所有观察者进行状态更新  
  13.     public void notifyObservers(Subject subject){  
  14.         for(Observer o:observers){  
  15.             o.update(subject);  
  16.         }  
  17.     }  
  18. }  
具体被观察者(ConcreteSubject)角色
[java] view plain copy
  1. public class ConcreteSubject extends Subject {  
  2.     //具体被观察者类可以具有自己的属性或状态  
  3.     private String state;  
  4.       
  5.     public String getState() {  
  6.         return state;  
  7.     }  
  8.     public void setState(String newState){  
  9.           
  10.         this.state = newState;  
  11.           
  12.         System.out.println("被观察者自身状态更新为:" + this.state);  
  13.           
  14.         //状态发生改变,通知所有观察者  
  15.         this.notifyObservers(this);  
  16.     }  
  17. }  
抽象观察者(Observer)角色
[java] view plain copy
  1. public interface Observer{  
  2.     //更新观察者的状态  
  3.     public void update(Subject subject);  
  4. }  
具体观察者(ConcreteObserver)角色
[java] view plain copy
  1. public class ConcreteObserverA implements Observer {  
  2.     private ConcreteSubject subject;  
  3.     public ConcreteSubject getSubject() {  
  4.         return subject;  
  5.     }  
  6.     public void setSubject(ConcreteSubject subject) {  
  7.         this.subject = subject;  
  8.     }  
  9.     @Override  
  10.     public void update(Subject subject) {  
  11.         this.subject=(ConcreteSubject)subject;  
  12.         System.out.println("观察者A中被观察对象的状态更新为:"+this.subject.getState());  
  13.     }  
  14. }  
[java] view plain copy
  1. public class ConcreteObserverB implements Observer {  
  2.     private ConcreteSubject subject;  
  3.     public ConcreteSubject getSubject() {  
  4.         return subject;  
  5.     }  
  6.     public void setSubject(ConcreteSubject subject) {  
  7.         this.subject = subject;  
  8.     }  
  9.     @Override  
  10.     public void update(Subject subject) {  
  11.         this.subject=(ConcreteSubject)subject;  
  12.         System.out.println("观察者B中被观察对象的状态更新为:"+this.subject.getState());  
  13.     }  
  14. }  
编写一个客户端来测试一番。
[java] view plain copy
  1. public class Client {  
  2.     public static void main(String[] args) {  
  3.         //创建被观察者对象  
  4.         ConcreteSubject subject=new ConcreteSubject();  
  5.         //创建观察者对象  
  6.         ConcreteObserverA observerA=new ConcreteObserverA();  
  7.         ConcreteObserverB observerB=new ConcreteObserverB();  
  8.         //为被观察者对象注册观察者  
  9.         subject.registerObserver(observerA);  
  10.         subject.registerObserver(observerB);  
  11.         subject.setState("复活中...");  
  12.         System.out.println();  
  13.         System.out.println("*************一千年以后...*************");  
  14.         System.out.println();  
  15.         subject.setState("疯狂杀戮中...");  
  16.     }  
  17. }  
运行程序打印结果如下:
[html] view plain copy
  1. 被观察者自身状态更新为:复活中...  
  2. 观察者A中被观察对象的状态更新为:复活中...  
  3. 观察者B中被观察对象的状态更新为:复活中...  
  4. *************一千年以后...*************  
  5. 被观察者自身状态更新为:疯狂杀戮中...  
  6. 观察者A中被观察对象的状态更新为:疯狂杀戮中...  
  7. 观察者B中被观察对象的状态更新为:疯狂杀戮中...  
四、Java对观察者模式的支持
在JAVA语言的java.util库里面有一个Observable类和一个Observer接口,通过两者配合使用可以实现观察者模式。
Observable类:
Observable中文意思“可以被观察的”,即Observable类是可以被观察的,想要实现观察者模式只需将你想要被观察的类继承自Observable类即可。
一个 Observable对象可以有一个或多个观察者,观察者可以是实现了Observer接口的任意对象。一个Observable对象状态改变后,会调用notifyObservers()方法来通知观察者。
以下是Observable类提供的一些常用方法:
[java] view plain copy
  1. public void addObserver(Observer o)    //向观察者集合中添加观察者  
  2. public void deleteObserver(Observer o)    //从观察者集合中删除某一个观察者  
  3. public void notifyObservers(Object arg)    //如果hasChanged方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来清除对象的已改变标记。此方法可不带参数,仅将Observable对象传递给update()方法,此时update方法中arg参数为Null。  
  4. public void deleteObservers()    //清除观察者列表,使此对象不再有任何观察者  
  5. protected void setChanged()    //标记Observable对象已经改变  
  6. protected void clearChanged()    //清除Observable对象已改变标记  
  7. public boolean hasChanged()    //测试对象是否改变  
  8. public int countObservers()    //返回Observable对象的观察者数目  
Observer接口:
Observer接口只包含一个update()方法,该方法仅接受两个参数:继承自Observable类的被观察对象和传递给notifyObservers() 方法的参数。当Observable(被观察者)对象状态发生改变时将通过notifyObservers()方法向所有的Observer(观察者)发送更新通知,Observer(观察者)对象在收到通知后即调用此方法完成状态更新。
[java] view plain copy
  1. void update(Observable o,  
  2.             Object arg)  
接下来我们举个简单的例子来演示一下如何使用Observable类和Observer接口实现观察者模式,去年2015年是牛市,炒股的基本都发家了,在此我们以炒股为例。
在炒股这个例子中,不用我说,相信你也想的到:股票Stock就是我们的被观察者。
[java] view plain copy
  1. import java.util.Observable;  
  2. public class Stock extends Observable{  
  3.     //为股票的状态创建一个枚举类:RISE 涨,FALL 跌  
  4.     public enum StockState{  
  5.         RISE,FALL  
  6.     }  
  7.     //股票涨跌状态  
  8.     private StockState state;  
  9.     //股票的价格  
  10.     private double price;  
  11.     //股票的历史最低价格  
  12.     private double LowestPrice;  
  13.     //股票无参的构造方法  
  14.     public Stock(){  
  15.     }  
  16.     //股票的带参数构造方法  
  17.     public Stock(StockState state, double price, double lowestPrice) {  
  18.         super();  
  19.         this.state = state;  
  20.         this.price = price;  
  21.         LowestPrice = lowestPrice;  
  22.     }  
  23.     public StockState getState() {  
  24.         return state;  
  25.     }  
  26.     private void setState(StockState state) {  
  27.         this.state = state;  
  28.     }  
  29.     public double getPrice() {  
  30.         return price;  
  31.     }  
  32.     public void setPrice(double price) {  
  33.         if(price<this.price){  
  34.             setState(StockState.FALL);  
  35.         }  
  36.         else{  
  37.             setState(StockState.RISE);  
  38.         }  
  39.         if(price<this.LowestPrice){  
  40.             setLowestPrice(price);  
  41.         }  
  42.         this.price = price;  
  43.         //更新股票状态标记为已改变  
  44.         this.setChanged();  
  45.         //通知观察者  
  46.         notifyObservers();  
  47.     }  
  48.     public double getLowestPrice() {  
  49.         return LowestPrice;  
  50.     }  
  51.     private void setLowestPrice(double lowestPrice) {  
  52.         LowestPrice = lowestPrice;  
  53.     }  
  54. }  
我们这些只有韭菜命的股民自然就是观察者了。
[java] view plain copy
  1. import java.util.Observable;  
  2. import java.util.Observer;  
  3. import com.ibeifeng.news.Stock.StockState;  
  4. public class Investor implements Observer {  
  5.     public void update(Observable o, Object arg) {  
  6.         Stock stock=(Stock)o;  
  7.         if(stock.getPrice()==stock.getLowestPrice())  
  8.         {  
  9.             System.out.println("股票已经跌到历史最低了,我得赶紧抄底...");  
  10.         }  
  11.         else{  
  12.             if(stock.getState().equals(StockState.RISE)){  
  13.                 System.out.println("股票在涨,目前价格:"+stock.getPrice());  
  14.             }  
  15.             else{  
  16.                 System.out.println("股票在跌,目前价格:"+stock.getPrice());  
  17.             }  
  18.         }  
  19.     }  
  20. }  
在客户端里面测试一下。
[java] view plain copy
  1. public class Client{  
  2.     public static void main(String[] args) {  
  3.         Stock stock=new Stock(StockState.FALL,14.7D,13.2D);  
  4.         stock.addObserver(new Investor());  
  5.         stock.setPrice(13.7);  
  6.         stock.setPrice(12.6);  
  7.         stock.setPrice(14.0);  
  8.     }  
  9. }  
运行程序打印结果如下:
[html] view plain copy
  1. 股票在跌,目前价格:13.7  
  2. 股票已经跌到历史最低了,我得赶紧抄底...  
  3. 股票在涨,目前价格:14.0  
五、观察者模式的优点
观察者Observer模式解决了对象之间一对多的复杂依赖关系问题,并使得程序易于维护与扩展。