我们都知道,蜜蜂是勤劳的精灵,它总是四处采蜜。只要花朵的花瓣一张开,她就飞上去采蜜。我们轻易就能想到,在这里,蜜蜂应该是一个观察者,而花朵是一个被观察者。只要花朵发生花瓣张开事件,就通知了观察者蜜蜂,蜜蜂就可以去采蜜了。
现在我们就来用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