Java设计模式之观察者模式

Java设计模式之观察者模式

      观察者模式书面表述是:观察者模式定义了对象间的一种一对多依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新,它将观察者和被观察者的对象分离开。提高了应用程序的可维护性和重用性。

在设计一组依赖的对象与它们所依赖的对象之间一致(同步)的交互模型时, 观察者模式(Observer Pattern)很有用。它可以使依赖对象的状态与它们所依赖的对象的状态保持同步。这组依赖的对象指的是观察者(Observer),它们所依赖的对象 称为主题(Subject)。为了实现观察者(Observer)与主题(Subject)的状态保持同步,应使用观察者模式。

观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。推荐采用发布者--订阅者(publisher--subscriber)模型,以使这组观察者和主题对象之间有清晰的界限, 对应关系为: publisher--subscriber -->> Subject--Observer。

常见的实例有:订阅模式(RSS),数据更新操作update(),Android端常用的广播模式

1.Observer角色分析

在观察者模式里有如下的角色:

 

抽象主题(Subject)角色:

主题角色是将观察者的对象的引用保存在一个集合或者列表中;每个主题都可以有任何数量的观察者。主题提供一个接口可以添加观察者和删除观察者的操作;主题角色又叫做抽象被观察者(Observable)角色;

抽象主题角色,有时又叫做抽象被观察者角色(Observable),采用接口或者抽象类来实现。

抽象观察者(Observer)角色:

这个角色就是用来实现数据更新行为的,是为观察者提供接口的行为,得到操作的请求后更新自己。                                      

抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。

具体主题(ConcreteSubject)角色:

保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;

具体主题角色,通常用一个具体子类实现。

具体观察者(ConcreteObserver)角色:

保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。

2.代码构造

 

1)      Subject 需要为注册和注销观察者分别提供一个接口(如add, remover接口)。

2)      Observer(观察者)需要提供一个可以从Subject接受通知的接口(如update,operate接口)。

Subject在状态发生变化时,利用改接口通知相应的Observer。

3)      下面的两点也需要满足:

(1)   拉模型(In the pull model)--主题需要提供一个接口,可以使观察者查询主题获得需要的状态信息来更新自己的状态。

(2)   推模型(In the push model)--主题发送观察者可能关注的状态信息。

3.实例模型

  仓库货物变更通知,举个简单的例子,有一辆载有大量的钞票和黄金的汽车从金库出发,因为是这个金额很大很大,所以出发的时候,要发送一个通知给特警和保安,但是在发送通知的时候多加了一个电话号码,恰好这个号码发送到了盗匪手中。这种demo中就是保安,劫匪,特警就是观察者,发出通知的就是抽象的主题,主题就是发送短信接口。

4.代码如下:

1.观察者接口 ObserverMethod
<span style="font-family:Courier New;font-size:18px;">public interface OberverMethod {
	
	void updata();

}</span>


2.观察者的三个角色
    1)保安角色

<span style="font-family:Courier New;font-size:18px;color:#6633ff;background-color: rgb(255, 255, 255);">public class ObjectOne implements OberverMethod{

	public void updata() {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护");  
	}
	

}</span>

    2)盗贼角色

<span style="background-color: rgb(255, 255, 255);"><span style="font-family:Courier New;font-size:18px;color:#6633ff;">public class ObjectTwo implements OberverMethod{

	public void updata() {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,注意随时准备炸弹,大干一票");  
	}

}</span></span>
    3)盗贼角色

<span style="font-family:Courier New;font-size:18px;color:#6633ff;">public class ObjectThress implements OberverMethod{


	public void updata() {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护"); 
	}


}</span>



3.被观察者接口行为Watche
 <span style="font-family:Courier New;">public interface Watche {
	
	 void addWatcher(OberverMethod watcher);  
	  
     void removeWatcher(OberverMethod watcher);  
 
     void notifyWatchers();  
}</span>

4.主题被观察者类实现了被观察者的接口OperacteWatche

<span style="font-family:Courier New;">public class OperacteWatche implements Watche {

	
	private List<OberverMethod> list = new ArrayList<OberverMethod>();  
	public synchronized  void addWatcher(OberverMethod watcher){
		if(watcher == null){
			throw new NullPointerException();
		}
		if(!list.contains(watcher)){
			list.add(watcher);
		}
		
	}

	public void removeWatcher(OberverMethod watcher) {
		list.remove(watcher);
		
	}

	public void notifyWatchers() {
		if(list != null && list.size() > 0){
			for(OberverMethod  entity : list ){
				if(entity != null){
					entity.updata();
				}
			}
		}
	}

}</span>
5.测试

<span style="font-family:Courier New;">Watche watche = new OperacteWatche();
		OberverMethod method1 = new ObjectOne();
		OberverMethod method2 = new ObjectTwo();
		OberverMethod method3 = new ObjectThress();
		System.out.println("全部通知");
		watche.addWatcher(method1);
		watche.addWatcher(method2);
		watche.addWatcher(method3);
	    watche.notifyWatchers();	
	    System.out.println("只通知保安和警察");
	    watche.removeWatcher(method2);
	    watche.notifyWatchers();</span>

6.输出结果:

全部通知
车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护
车号:闽AAA888,有大量的现金和黄金,注意随时准备炸弹,大干一票
车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护
只通知保安和警察
车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护
车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护


总结:该实例,是一种简单的观察者模式的情景,保安,特警,盗匪三者就是观察者角色,都是实现一个ObserverMethod这个观察者接口,调用update方法时会实现自己想要执行的行为,被观察者是来通知观察者对象执行相应的操作的,同时提供了添加和删除观察者角色的功能。通过一对多的关系实现了通知的功能。

2 Java jdk中的观察者的封装

 Java语言对观察者模式的支持

Java语言的java.util库里面,提供了一个Observable类以及一个Observer接口(Java.util.Observer/ Java.util.Observable),构成Java语言对观察者模式的支持。我们只需要直接实现他们就可以。

Observer接口

  这个接口只定义了一个方法,update()。当被观察者对象的状态发生变化时,这个方法就会被调用。这个方法的实现应当调用每一个被观察者对象的notifyObservers()方法,从而通知所有的观察对象。

 

<span style="font-family:Courier New;font-size:18px;color:#6600cc;"></span><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Courier New';font-size:13.5pt;"><span style="color:#629755;"><em></em></span><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Courier New';font-size:13.5pt;"><span style="color:#ccc92c;">package </span>java.<span style="background-color:#344134;">util</span><span style="color:#cc7832;">;</span>
/** * { @code Observer} is the interface to be implemented by objects that * receive notification of updates on an { @code Observable} object. * * @see Observable */ public interface Observer { /** * This method is called if the specified { @code Observable} object's * { @code notifyObservers} method is called (because the { @code Observable} * object has been updated. * * @param observable * the { @link Observable} object. * @param data * the data passed to { @link Observable#notifyObservers(Object)}. */ void update(Observable observable , Object data) ;}

 
 
 
 

Observable类

直译:观察是用来通知一组观察对象时,一个变化
发生。在创作上,一系列的观察者是空的。发生变化后,
应用程序可以调用{@链接# notifyobservers() }方法。这将
因为所有的注册代码update() } {”方法的调用
观察员。未指定调用顺序。这个实现会
称为观察员的命令,他们注册。子类是完全
免费的,他们称之为更新方法。

 从源码中可以看出,被观察者类都是Java.util.Observable的子类,java.util.Observable提供了公开的方法来提供支持观察者对象,常规的方法有addObserver(Observer);deleteObserver(Observer );以及通知更新的方法notifyObservers(); 在使用的使用同时要注意一个特别重要的方法,setChanged();在通知更新前如果不调用这个方法的话就不会执行notifyObservers()方法,所以不会出现更新操作。由于该方法是保护的方法,所以我们通常的使用时继承Observable类来执行操作。

 

package java.util;
/** * Observable is used to notify a group of Observer objects when a change * occurs. On creation, the set of observers is empty. After a change occurred, * the application can call the {@link #notifyObservers()} method. This will * cause the invocation of the {@code update()} method of all registered * Observers. The order of invocation is not specified. This implementation will * call the Observers in the order they registered. Subclasses are completely * free in what order they call the update methods. * * @see Observer */public class Observable { List<Observer> observers = new ArrayList<Observer>(); boolean changed = false; /** * Constructs a new {@code Observable} object. */ public Observable() { } /** * Adds the specified observer to the list of observers. If it is already * registered, it is not added a second time. * * @param observer * the Observer to add. */ public void addObserver(Observer observer) { if (observer == null) { throw new NullPointerException("observer == null"); } synchronized (this) { if (!observers.contains(observer)) observers.add(observer); } } /** * Clears the changed flag for this {@code Observable}. After calling * {@code clearChanged()}, {@code hasChanged()} will return {@code false}. */ protected void clearChanged() { changed = false; } /** * Returns the number of observers registered to this {@code Observable}. * * @return the number of observers. */ public int countObservers() { return observers.size(); } /** * Removes the specified observer from the list of observers. Passing null * won't do anything. * * @param observer * the observer to remove. */ public synchronized void deleteObserver(Observer observer) { observers.remove(observer); } /** * Removes all observers from the list of observers. */ public synchronized void deleteObservers() { observers.clear(); } /** * Returns the changed flag for this {@code Observable}. * * @return {@code true} when the changed flag for this {@code Observable} is * set, {@code false} otherwise. */ public boolean hasChanged() { return changed; } /** * If {@code hasChanged()} returns {@code true}, calls the {@code update()} * method for every observer in the list of observers using null as the * argument. Afterwards, calls {@code clearChanged()}. * <p> * Equivalent to calling {@code notifyObservers(null)}. */ public void notifyObservers() { notifyObservers(null); } /** * If {@code hasChanged()} returns {@code true}, calls the {@code update()} * method for every Observer in the list of observers using the specified * argument. Afterwards calls {@code clearChanged()}. * * @param data * the argument passed to {@code update()}. */ @SuppressWarnings("unchecked") public void notifyObservers(Object data) { int size = 0; Observer[] arrays = null; synchronized (this) { if (hasChanged()) { clearChanged(); size = observers.size(); arrays = new Observer[size]; observers.toArray(arrays); } } if (arrays != null) { for (Observer observer : arrays) { observer.update(this, data); } } } /** * Sets the changed flag for this {@code Observable}. After calling * {@code setChanged()}, {@code hasChanged()} will return {@code true}. */ protected void setChanged() { changed = true; }}

依据上面的实例,代码如下:


角色1. ObjectOne 

<span style="font-family:Courier New;font-size:18px;color:#6633ff;background-color: rgb(255, 255, 255);">public class ObjectOne implements Observer{

//	public void updata() {
//		System.out.println("车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护");  
//	}

	public void update(Observable o, Object arg) {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护");  
		
	}
	

}</span>


角色2 ObjectTwo 

<span style="font-family:Courier New;font-size:18px;color:#6633ff;">public class ObjectTwo implements Observer{

	public void updata() {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,注意随时准备炸弹,大干一票");  
	}

	public void update(Observable o, Object arg) {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,注意随时准备炸弹,大干一票");  
		
	}

}</span>

角色3 ObjectThress 

<span style="font-family:Courier New;font-size:18px;color:#6633ff;">public class ObjectThress implements Observer{

//	public void updata() {
//		System.out.println("车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护"); 
//	}

	public void update(Observable o, Object arg) {
		System.out.println("车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护"); 
	}

}</span>


被观察者类 OperateObservable  

<span style="font-family:Courier New;font-size:18px;color:#6633ff;">public class OperateObservable extends Observable {

	@Override
	public synchronized void addObserver(Observer o) {
		super.addObserver(o);
	}

	@Override
	protected synchronized void clearChanged() {
		super.clearChanged();
	}

	@Override
	public synchronized void deleteObserver(Observer o) {
		super.deleteObserver(o);
	}

	@Override
	public synchronized void deleteObservers() {
		super.deleteObservers();
	}

	@Override
	public void notifyObservers() {
		super.setChanged();
		super.notifyObservers();
	}

	@Override
	public void notifyObservers(Object arg) {
		super.notifyObservers(arg);
	}

	@Override
	protected synchronized void setChanged() {
		super.setChanged();
	}
}</span>
测试:



<span style="font-family:Courier New;font-size:18px;color:#6633ff;">OperateObservable observer = new OperateObservable();
<span style="white-space:pre">		</span>Observer  roleone= new ObjectOne();
<span style="white-space:pre">		</span>Observer roletwo = new ObjectTwo();
<span style="white-space:pre">		</span>Observer rolethree = new ObjectThress();
<span style="white-space:pre">		</span>observer.addObserver(roleone);
<span style="white-space:pre">		</span>observer.addObserver(roletwo);
<span style="white-space:pre">		</span>observer.addObserver(rolethree);
<span style="white-space:pre">		</span>System.out.println("全部通知");
//<span style="white-space:pre">		</span>observer.setChanged();
<span style="white-space:pre">		</span>observer.notifyObservers();
<span style="white-space:pre">		</span>observer.deleteObserver(roletwo);
<span style="white-space:pre">		</span>System.out.println("只通知保安和警察");
//<span style="white-space:pre">		</span>observer.setChanged();
<span style="white-space:pre">		</span>observer.notifyObservers();</span>


运行结果:

全部通知
车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护
车号:闽AAA888,有大量的现金和黄金,注意随时准备炸弹,大干一票
车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护
只通知保安和警察
车号:闽AAA888,有大量的现金和黄金,特警提高警惕,贴身保护
车号:闽AAA888,有大量的现金和黄金,保安提高警惕,贴身保护

3 观察者模式在Android中运用


  在Android平台使用观察者模式的情况很多,常见的就是广播机制,广播机制通过提供注册,然后当发出通知后,所有接受者都会得到响应。接受者就相当于观察者的角色,发送广播的类相当于被观察者的角色。还有ViewGroup的机制中监听子View的大小或者位置发生变化的操作,如果子View的大小或者位置发生变化,父类就会感受到得到子View发生变化的通知。在Android平台很多的场合中都使用了观察者模式来做了Api的封装。 才开始写文章,感觉写的很乱,希望你们不吝赐教,谢谢。



4 观察者模式优缺点



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

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

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

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

 

观察者模式有下面的缺点

第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。

第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。

第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的,仅仅知道发生了什么变化而已。

才开始写文章,感觉写的很乱,希望你们不吝赐教,谢谢。









































3 观察者模式在Android中运用

你可能感兴趣的:(java,android,java设计模式)