Java程序员从笨鸟到菜鸟之(三十六)大话设计模式(六)观察者模式

来源:互联网 发布:阿里巴巴网络销售招聘 编辑:程序博客网 时间:2024/05/02 21:52

本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188        

 

         Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。《设计模式》一书对Observer是这样描述的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并自动更新。别名:依赖(Dependents)、发布-订阅(Publish-Subscribe)

下面我们就来看看观察者模式的组成部分。

1) 抽象目标角色(Subject):目标角色知道它的观察者,可以有任意多个观察者观察同一个目标。并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口来实现。

2) 抽象观察者角色(Observer):为那些在目标发生改变时需要获得通知的对象定义一个更新接口。抽象观察者角色主要由抽象类或者接口来实现。

3)具体目标角色(Concrete Subject):将有关状态存入各个Concrete Observer对象。当它的状态发生改变时向它的各个观察者发出通知。

4) 具体观察者角色(Concrete Observer):存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口以使自身状态与目标的状态保持一致。在本角色内也可以维护一个指向Concrete Subject对象的引用。

结构如下:

观察者模式的优缺点:

观察者模式的效果有以下的优点

  第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。

  由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。

  第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知,

观察者模式有下面的缺点

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

下面用程序来说明一下观察者模式的流程:

一个随机数产生对象和两个观察者,这两个观察者都在随机数产生对象那里注册了,意思说如果你产生了新的数字,就通知我一声。

 

结构图:

类说明 

 名称

 功能说明

 Observer

 表示观察者的接口,要成为观察者必须实现此接口才行

 NumberGenerator

 表示产生数值的抽象类

 RandomNumberGenerator

 产生随机数的类,继承于NumberGenerator

 NumberObserver

 数字观察者,会打印出变化的数字

 SymbolObserver

 符号观察者,打印个符号,打印多少个符号,由接受到的数值确定

 

1.Observer

package com.pattern.observer;public interface Observer {public abstract void update(NumberGenerator generator);}


2.NumberGenerator

 

package com.pattern.observer;import java.util.ArrayList;import java.util.Iterator;/** * @project JavaPattern * @author sunnylocus * @verson 1.0.0 * @date   Aug 27, 2008 1:35:34 PM * @description 产生数值的抽象类 */public abstract class NumberGenerator {private ArrayList observers = new ArrayList();  //存储Observer/** 添加观察者*/public void addObserver(Observer observer) {observers.add(observer);}/** 删除观察者*/public void delObserver(Observer observer) {observers.remove(observer);}/** 通知所有观察者*/public void notifyObservers() {Iterator it = observers.iterator();while(it.hasNext()) {Observer o =(Observer) it.next();o.update(this);//this相当于上面提到的邮局名}}public abstract int getNumber();//获取数字public abstract void generate();//产生数字}


3.RandomNumberGenerator

package com.pattern.observer;import java.util.Random;/** * @project JavaPattern * @author sunnylocus * @verson 1.0.0 * @date   Aug 27, 2008 1:48:03 PM * @description 用于产生随机数及通知观察者的类 */public class RandomNumberGenerator extends NumberGenerator{private Random random = new Random();//随机数产生器private int number;   //用于存放数字public void generate() {for(int i=0 ; i < 5; i++) {number = random.nextInt(10);//产生10以内的随机数notifyObservers();  //有新产生的数字,通知所有注册的观察者}}    /** 获得数字*/public int getNumber() {return number;}}


4.NumberObserver

 package com.pattern.observer;/** 以数字表示观察者的类*/public class NumberObserver implements Observer{public void update(NumberGenerator generator) {System.out.println("NumberObserver:"+ generator.getNumber());try {Thread.sleep(1000 * 3); //为了能清楚的看到输出,休眠3秒钟。}catch(InterruptedException e) {e.printStackTrace();}}}


5.SymbolObserver

package com.pattern.observer;/** 以符号表示观察者的类*/public class SymbolObserver implements Observer{public void update(NumberGenerator generator) {System.out.print("SymbolObserver:");int count = generator.getNumber();for(int i = 0 ; i < count; i ++) {System.out.print("*^_^*  ");}System.out.println("");try {Thread.sleep(1000 * 3);}catch(InterruptedException e){e.printStackTrace();}}}


6.Main(测试类) 

package com.pattern.observer;public class Main {public static void main(String[] args) {//实例化数字产生对象NumberGenerator generator = new RandomNumberGenerator();//实例化观察者Observer observer1 = new NumberObserver();Observer observer2 = new SymbolObserver();//注册观察者generator.addObserver(observer1);generator.addObserver(observer2);generator.generate(); //产生数字}}


 7.结果输出