jdk自带的观察者模式

介绍一下jdk自带的观察者模式

subject -> java.util.Observable(类)

void addObserver(Observer o) 
          如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。 
protected  void clearChanged() 
          指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所以 hasChanged 方法将返回 false。 
int countObservers() 
          返回 Observable 对象的观察者数目。 
void deleteObserver(Observer o) 
          从对象的观察者集合中删除某个观察者。 
void deleteObservers() 
          清除观察者列表,使此对象不再有任何观察者。 
boolean hasChanged() 
          测试对象是否改变。 
void notifyObservers() 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 
void notifyObservers(Object arg) 
          如果 hasChanged 方法指示对象已改变,则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。 
protected  void setChanged() 
          标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true。

observer -> java.util.Observer(接口)

void update(Observable o, Object arg) 
          只要改变了 observable 对象就调用此方法。 

需要特别说明下setChanged()、chearChanged()和hasChanged()这3个方法:

参见上面Observable类的notifyObservers(Object arg)方法,hasChanged()为true才会通知观察者数据有变化,并且在通知完成之后调用clearChanged()修改hasChanged()为false,所以当主题数据改变时,需要先调用setChanged()方法使hasChanged为true

Observable的伪码应该如下所示:

public class Observable {
	private boolean flag = false;
	private List<Observer> list = new ArrayList<Observer>();
	
	public boolean hasChanged(){
		return flag;
	}
	
	protected void setChanged(){
		flag = true;
	}

	protected void clearChanged(){
		flag = false;
	}
	
	public void addObserver(Observer o){
		if(!list.contain(o)){
			list.add(o);
		}
	}
	
	public void deleteObserver(Observer o){
		if(list.contain(o)){
			list.remove(o);
		}
	}
	
	public void notifyObservers(Object arg){
		if(hasChanged()){
			if(null != list && list.size > 0){
				for(Observer o : list){
					o.update(this, arg);
				}
			}
		}
		clearChanged();
	}
}
public class SpecialRepoter extends Observable {
	public void getNewNews(String msg){
		if(msg.length()>100){
			this.setChanged();
		}
		this.notifyObservers(msg);
	}
}

通过这段伪代码可以很清楚的了解这3个方法了,这3个方法使我们对何时进行push进行精确控制,在我们不想推送的时候,不调用setChanged()方法即可

使用jdk自带的观察者模式重写一下以前的记者和报社例子:

想要进行通知,则必须调用Observable类的setChanged方法,但是Observable的setChanged方法为protected,故只能使用继承来实现自己的主题对象

主题继承自Observable类,观察者实现Observer接口,并且主题需要的方法已经在Observable类中实现了

public class SpecialRepoter extends Observable {
	public void getNewNews(String msg){
		this.setChanged();
		this.notifyObservers(msg);
	}
}
public class NewspaperOffice {
}
public class PeopleDaily extends NewspaperOffice implements Observer {
	private Observable observable;
	
	public PeopleDaily(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			System.out.println("People's Daily brings you the latest news!");  
		}
	}
	
	public void remove(){
		observable.deleteObserver(this);
	}
}
public class XinhuaDaily extends NewspaperOffice implements Observer{
	private Observable observable;
	
	public XinhuaDaily(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			System.out.println("Xinhua Daily brings you the latest news!");
		}
	}
}
public class GlobalTimes extends NewspaperOffice implements Observer{
	private Observable observable;
	
	public GlobalTimes(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			System.out.println("Global Timse brings you the latest news!");	
		}
	}
}

测试一下:

public class Test {
	public static void main(String[] args) {
		SpecialRepoter repoter = new SpecialRepoter();
		GlobalTimes n1 = new GlobalTimes(repoter);
		PeopleDaily n2 = new PeopleDaily(repoter);
		XinhuaDaily n3 = new XinhuaDaily(repoter);
		
		repoter.getNewNews("new news!");
		n2.remove();
		repoter.getNewNews("another new news!");
	}
}
Xinhua Daily brings you the latest news!
People's Daily brings you the latest news!
Global Timse brings you the latest news!
Xinhua Daily brings you the latest news!
Global Timse brings you the latest news!

在注册的时候,先注册的GlobalTimes,然后是PeopleDaily,最后才是XinhuaDaily,但是最后结果打印的却不是这个顺序,可以看出通知顺序和注册的顺序没有关系,即通知顺序不依赖于注册的顺序,这要特别注意

下面使用Observer Pattern的pull模式再次重写:

public class SpecialRepoter extends Observable {
	private String msg;
	
	public void getNewNews(String msg){
		this.msg = msg;
		this.setChanged();
		this.notifyObservers();
	}
	
	public String getMsg(){
		return msg;
	}
}
public class NewspaperOffice {
}
public class PeopleDaily extends NewspaperOffice implements Observer {
	private Observable observable;
	
	public PeopleDaily(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			SpecialRepoter repoter = (SpecialRepoter)o;
			String msg = repoter.getMsg();
			System.out.println("People's Daily brings you the latest news!");  
			System.out.println(msg.toString());
		}
	}
	
	public void remove(){
		observable.deleteObserver(this);
	}
}
public class XinhuaDaily extends NewspaperOffice implements Observer{
	private Observable observable;
	
	public XinhuaDaily(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			SpecialRepoter repoter = (SpecialRepoter)o;
			String msg = repoter.getMsg();
			System.out.println("Xinhua Daily brings you the latest news!");
			System.out.println(msg.toString());
		}
	}
}
public class GlobalTimes extends NewspaperOffice implements Observer{
	private Observable observable;
	
	public GlobalTimes(SpecialRepoter repoter){
		this.observable = repoter;
		repoter.addObserver(this);
	}

	public void update(Observable o, Object arg) {
		if(o instanceof SpecialRepoter){
			SpecialRepoter repoter = (SpecialRepoter)o;
			String msg = repoter.getMsg();
			System.out.println("Global Timse brings you the latest news!");	
			System.out.println(msg.toString());
		}
	}
}

测试一下:

public class Test {
	public static void main(String[] args) {
		SpecialRepoter repoter = new SpecialRepoter();
		GlobalTimes n1 = new GlobalTimes(repoter);
		PeopleDaily n2 = new PeopleDaily(repoter);
		XinhuaDaily n3 = new XinhuaDaily(repoter);
		
		repoter.getNewNews("new news!");
		n2.remove();
		repoter.getNewNews("another new news!");
	}
}
Xinhua Daily brings you the latest news!
new news!
People's Daily brings you the latest news!
new news!
Global Timse brings you the latest news!
new news!
Xinhua Daily brings you the latest news!
another new news!
Global Timse brings you the latest news!
another new news!

 

ps:

使用jdk自带的观察者模式的缺点:

1,Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活

2,Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能


 

 

 

 

posted @ 2013-05-26 19:00  心意合一  阅读(359)  评论(0编辑  收藏  举报