我们都知道,蜜蜂是勤劳的精灵,它总是四处采蜜。只要花朵的花瓣一张开,她就飞上去采蜜。我们轻易就能想到,在这里,蜜蜂应该是一个观察者,而花朵是一个被观察者。只要花朵发生花瓣张开事件,就通知了观察者蜜蜂,蜜蜂就可以去采蜜了。
现在我们就来用java程序模拟蜜蜂采蜜。
Java的API为我们设计好了这个模式,我们的被观察者需要继承Observable类,而观察者需要实现Observer接口。
现在我们来看看实际的代码:
package observer;
 
import java.util.Observable;
import java.util.Observer;
 
public class Flower extends Observable
{
      public void open()          -----------------------------------------------1
      {
               System.out.println("The flower is opening!");   -----------2
               this.setChanged();        ----------------------------------------3
               this.notifyObservers();   ---------------------------------------4
      }
      public void registObserver(Observer observer)   -------------------5
      {
               this.addObserver(observer);            --------------------------6
      }
 
      public static void main(String[] args)
      {
      }
}
 
标号1行定义了一个方法,在这个方法里,主要要做三件事:第一被观察者的动作,见标号2行的代码;第二设置被观察者的状态变化,如标号3行的代码;第三通知观察者,如标号4行的代码。
package observer;
 
import java.util.Observable;
import java.util.Observer;
 
public class Bee implements Observer
{
 
      public void update(Observable arg0, Object arg1)
      {
               // TODO Auto-generated method stub
               System.out.println("It is bee's meat time!");
 
      }
      public static void main(String[] args)
      {
      }
}
观察者的实现比较简单,主要就是要实现update方法,在这个方法里实现观察者在观察到被观察者动作后所要做的动作。
下面是测试代码:
Bee bee = new Bee();
               Flower flower = new Flower();
               flower.registObserver(bee);
               flower.open();
测试结果如下:
The flower is opening! 
It is bee's meat time! 
现在我们已经基本熟悉了观察家模式的用法,可以用它来设计我们一些日常所见的现象。如我们常说的一句成语是“螳螂捕蝉,黄雀在后”就可以利用我们的观察家模式来进行设计。螳螂在四处搜寻着蝉,如果蝉趴在树枝上一动不动,那么螳螂是很难发现蝉。但如果蝉一有动作,就会被螳螂发现;螳螂一旦发现蝉,就会对蝉发起攻击;但螳螂万万没有想到,黄雀也在后面搜寻着螳螂,一旦螳螂有所动作,黄雀也会对螳螂发动攻击。 
很明显,蝉是一个被观察者,而黄雀是一个观察者,螳螂则对蝉来说是一个观察者,对黄雀来说是一个被观察者,所以螳螂既是观察者又是被观察者。 
代码如下: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public class Cicada extends Observable 
{ 
  public void move() 
  { 
      System.out.println("The cicada is moving...."); 
      this.setChanged(); 
      this.notifyObservers(); 
  } 
  public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
 
  public static void main(String[] args) 
  { 
  } 
} 
 
 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
 
public class DevilHorse extends Observable implements Observer 
{ 
  public void update(Observable arg0, Object arg1) 
  { 
      // TODO Auto-generated method stub 
      System.out.println("It is time for Devil horse to attack...."); 
      this.setChanged(); 
      this.notifyObservers(); 
 
  } 
  public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
  public static void main(String[] args) 
  { 
  } 
} 
 
 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public class YellowBird implements Observer 
{ 
  public void update(Observable arg0, Object arg1) 
  { 
      // TODO Auto-generated method stub 
      System.out.println("It is time for a yellow bird to attrack...."); 
 
  } 
 
  public static void main(String[] args) 
  { 
       
  } 
} 
 
在上面的代码中,类DevilHorse既是观察者,又是被观察者,所以它既继承了Observable类,又实现了Observer接口。 
下面是测试代码: 
Cicada cicada = new Cicada(); 
      DevilHorse devilHorse = new DevilHorse(); 
      YellowBird yellowBird = new YellowBird(); 
      cicada.registObserver(devilHorse); 
      devilHorse.registObserver(yellowBird); 
      cicada.move(); 
运行结果: 
The cicada is moving.... 
It is time for Devil horse to attack.... 
  It is time for a yellow bird to attrack.... 
 
到了上面为止,我们已经把观察家模式全面的剖析了一遍。现在来对该模式作一些深入的研究。 
我们还是以蜜蜂采花为例,现在我们加入鸟儿吃蜂这一个案例。很明显,我们的Flower类不用变,而Bee类则既是观察者又是被观察者,需要做改动为如下代码: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public class Bee extends Observable implements Observer 
{ 
  public void update(Observable arg0, Object arg1) 
  { 
      // TODO Auto-generated method stub 
      System.out.println("It is bee's meat time!"); 
      this.setChanged(); 
      this.notifyObservers(); 
 
  } 
  public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
 
  public static void main(String[] args) 
  { 
  } 
} 
而Bird类为: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public class Bird implements Observer 
{ 
 
  public void update(Observable arg0, Object arg1) 
  { 
      // TODO Auto-generated method stub 
      System.out.println("It is a bird's meat time...."); 
 
  } 
 
  public static void main(String[] args) 
  { 
  } 
} 
 
测试代码: 
Bee bee = new Bee(); 
      Bird bird = new Bird(); 
      Flower flower = new Flower(); 
      flower.registObserver(bee); 
      bee.registObserver(bird); 
      flower.open(); 
测试结果: 
The flower is opening! 
It is bee's meat time! 
  It is a bird's meat time.... 
 
我们看看上面的被观察者类,方法: 
public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
每次都被原封不动的照抄下来;而在被观察者的动作方法里头,总有 
this.setChanged(); 
      this.notifyObservers(); 
这两句是必须照抄的。 
每一个被观察者都必须这样,很明显,这是冗余代码,我们需要想办法解决。对于这样的冗余代码,我们可以轻松的想到用模板方法模式来解决。 
还有,我们来看测试代码,我们对类的初始化都有很明显的局限性。如: 
Bee bee = new Bee(); 
      Bird bird = new Bird(); 
      Flower flower = new Flower(); 
flower.registObserver(bee); 
我们来看flower和bee的依赖关系,我们都知道依赖颠倒原则说的是要依赖抽象而不要依赖具体实现,而flower和bee的依赖明显是依赖具体实现bee,不满足依赖颠倒原则。这带来的缺点也是显而易见的:如果有一个蝴蝶类也在观察着Flower类,那么在运行期才能知道Flower类的观察者,该怎么办? 
以上的两个缺点需要我们对观察家模式作进一步的包装。 
我们首先对被观察者作包装,代码如下: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public abstract class BaseObservable extends Observable 
{ 
  protected void baseDo() 
  { 
      observableDo(); 
      this.setChanged(); 
      this.notifyObservers(); 
  } 
  public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
  public abstract void observableDo(); 
} 
BaseObservable类是一个模板方法模式的一个直接应用。我们的被观察者只要继承了这个类,就只需实现observableDo即可,在该方法里只写被观察者的动作,而无须关注其他。 
然后是对既是观察者又是被观察者的类进行包装: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
 
public abstract class BaseObservableObserver extends Observable implements Observer 
{ 
  public void update(Observable arg0, Object arg1) 
  { 
      // TODO Auto-generated method stub 
      observableObserverDo(arg0,arg1); 
      this.setChanged(); 
      this.notifyObservers(); 
 
  } 
  public void registObserver(Observer observer) 
  { 
      this.addObserver(observer); 
  } 
  public abstract void observableObserverDo(Observable arg0, Object arg1); 
 
  public static void main(String[] args) 
  { 
  } 
} 
同样,我们的观察和被观察者只要继承了BaseObservableObserver类,就只要实现observableObserverDo方法即可,在这个方法里头实现它的动作。 
最后是对观察者的包装: 
package observer; 
 
import java.util.Observable; 
import java.util.Observer; 
public abstract class BaseObserver implements Observer 
{ 
  public void update(Observable arg0, Object arg1) 
  { 
      ObserverDo(arg0,arg1); 
  } 
  public abstract void ObserverDo(Observable arg0, Object arg1); 
  public static void main(String[] args) 
  { 
  } 
} 
同样,观察者只要继承了BaseObserver类,就只要在ObserverDo方法里实现观察家的动作就好了。 
下面我们来重新设计Flower、Bee和Bird类: 
package observer; 
 
public class Flower extends BaseObservable 
{ 
  public void observableDo() 
  { 
      System.out.println("The flower is opening..."); 
  } 
} 
 
package observer; 
 
import java.util.Observable; 
 
public class Bee extends BaseObservableObserver 
{ 
  public void observableObserverDo(Observable arg0, Object arg1) 
  { 
      System.out.println("It is a bee's meal time..."); 
  } 
} 
 
package observer; 
 
import java.util.Observable; 
 
public class Bird extends BaseObserver 
{ 
  public void ObserverDo(Observable arg0, Object arg1) 
  { 
      System.out.println("aha,it's a bird's meal time..."); 
  } 
} 
 
现在我们可以看到这三个类简洁了很多,只有和业务相关的动作方法,来看我们的测试类: 
BaseObservable flower = new Flower(); 
      BaseObservableObserver bee = new Bee(); 
      BaseObserver bird = new Bird(); 
      flower.registObserver(bee); 
      bee.registObserver(bird); 
      flower.baseDo(); 
测试结果: 
The flower is opening... 
It is a bee's meal time... 
  aha,it's a bird's meal time... 
 
我们可以看到,flower和bee的依赖关系也由具体类Bee变成了抽象类BaseObservableObserver。有利于我们的系统扩展。 
如,我们增加了一个Butterfly类: 
package observer; 
 
import java.util.Observable; 
 
public class Butterfly extends BaseObservableObserver 
{ 
  public void observableObserverDo(Observable arg0, Object arg1) 
  { 
      System.out.println("The butterfly is coming for a meal..."); 
  } 
} 
 
我们的测试端就可以有这样的代码: 
BaseObservable flower = new Flower(); 
      BaseObservableObserver bee = new Bee(); 
      BaseObservableObserver butterfly = new Butterfly(); 
      BaseObserver bird = new Bird(); 
      ArrayList list = new ArrayList(); 
      list.add(bee); 
      list.add(butterfly); 
      for(int i=0;i<list.size();i++) 
      { 
           BaseObservableObserver boo = (BaseObservableObserver)list.get(i); 
           flower.registObserver(boo); 
           boo.registObserver(bird); 
      } 
      flower.baseDo(); 
这样使得观察家模式更加灵活和易于扩展。 
测试结果: 
The flower is opening... 
The butterfly is coming for a meal... 
aha,it's a bird's meal time... 
It is a bee's meal time... 
  aha,it's a bird's meal time... 
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=547850