`
lastsoul
  • 浏览: 33318 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

观察者模式

 
阅读更多
GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。
适用性

    1.当一个抽象模型有两个方面,其中一个方面依赖于另一方面。

      将这二者封装到独立的对象中以使它们可以各自独立地改变和复用。

    2.当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。

    3.当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望

这些对象是紧密耦合的。

  参与者

   .抽象主题(Subject)角色:主题角色把所有的观察者对象的引用保存在一个列表里;

每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角

色又叫做抽象被观察者(Observable)角色;
 
. 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到通知时更新自己;
   . 具体主题(ConcreteSubject)角色:保存对具体观察者对象有用的内部状态;在这

种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;

   .具体观察者(ConcreteObserver)角色:保存一个指向具体主题对象的引用;和一

个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,

以便使本身的状态与主题的状态自恰。

示例代码:
1.抽象主题角色类
package com.observe;

public interface AbstractWatched {
	
	//增加一个观察者
	public void addAbstactWatcher(AbstractWatcher watcher);
	
	//移除一个观察者
	public void removeAbstactWatcher(AbstractWatcher watcher);
	
	//移除所有的观察着
	public void removeAll();
	
	//通知所有的观察者
	public void notifyWatchers();

}

2.抽象观察者角色
package com.observe;

public interface AbstractWatcher {
	
	public void update();

}

3.具体主题角色(Watched)
package com.observe;

import java.util.ArrayList;
import java.util.List;

public class ConcreteWatched implements AbstractWatched {

	//list:存放观察者的一个集合对象
	List<AbstractWatcher> list = new ArrayList<AbstractWatcher>();
	
	//增加一个观察者
	public void addAbstactWatcher(AbstractWatcher watcher) {
		list.add(watcher);

	}

	//移除一个观察者
	public void removeAbstactWatcher(AbstractWatcher watcher) {
		list.remove(watcher);

	}

	//移除所有的观察着
	public void removeAll() {
		list.clear();

	}
	
	//通知所有的观察者
	public void notifyWatchers() {
		for(AbstractWatcher watcher : list){
			watcher.update();
		}

	}

}

4.具体观察者角色(Watcher)
package com.observe;


public class ConcreteWatcher implements AbstractWatcher {

	//观察到被观察者发生变化时,执行的方法
	public void update() {
		System.out.println("update.....");
		
	}
	
	

}

5.客户端调用:
package com.observe;

public class ClientTest {

	public static void main(String[] args){
		//定义一个被观察者对象
		AbstractWatched watched = new ConcreteWatched();
		
		//定义三个观察者对象
		AbstractWatcher watcher1 = new ConcreteWatcher();
		AbstractWatcher watcher2 = new ConcreteWatcher();
		AbstractWatcher watcher3 = new ConcreteWatcher();
		
		//被观察者添加观察者. 被观察者和观察者之间关系是一对多关系
		watched.addAbstactWatcher(watcher1);
		watched.addAbstactWatcher(watcher2);
		watched.addAbstactWatcher(watcher3);
		
		System.out.println("第1次...");
		//被观察者发生改变时,通知观察者执行相应方法
		watched.notifyWatchers();
		
		//移除一个观察者
		watched.removeAbstactWatcher(watcher2);
		
		System.out.println("第2次...");
		//被观察者发生改变时,通知观察者执行相应方法
		watched.notifyWatchers();
		
		//移除一个所有观察者
		watched.removeAll();
		
		System.out.println("第3次...");
		//被观察者发生改变时,通知观察者执行相应方法
		watched.notifyWatchers();
		
	}
}

执行结果为:
第1次... 
update..... 
update..... 
update..... 
第2次... 
update..... 
update..... 
第3次... 


推模型和拉模型

       在观察者模式的实现里面,又分为推模型和拉模型两种方式。
推模型

    目标对象主动向观察者推送目标的详细信息,不管观察者是否需要,推送的信息通常是目

标对象的全部或部分数据,相当于是在广播通信。实现方法就是,update 方法加一个参

数,通过这个参数把数据传过去。

拉模型

    目标对象在通知观察者的时候,只传递少量信息,如果观察者需要更具体的信息,由观察

者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。
  
一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者,这样在观察者

需要获取数据的时候,就可以通过这个引用来获取了。

观察者模式的优缺点

          观察者模式实现了观察者和目标之间的抽象耦合

原本目标对象在状态发生改变的时候,需要直接调用所有的观察者对象,但是抽象出观察者接

口过后,目标和观察者就只是在抽象层面上耦合了,也就是说目标只是知道观察者接口,并不

知道具体的观察者的类,从而实现目标类和具体的观察者类之间解耦。

           观察者模式实现了动态联动
    所谓联动,就是做一个操作会引起其它相关的操作。由于观察者模式对观察者注册实行管

理,那就可以在运行期间,通过动态的控制注册的观察者,来控制某个动作的联动范围,从而

实现动态联动。

        观察者模式支持广播通信
   
由于目标发送通知给观察者是面向所有注册的观察者,所以每次目标通知的信息就要对所有注

册的观察者进行广播。当然,也可以通过在目标上添加新的功能来限制广播的范围。
 
  在广播通信的时候要注意一个问题,就是相互广播造成死循环的问题。比如A和B两个对象

互为观察者和目标对象,A对象发生状态变化,然后A来广播信息,B对象接收到通知后,在处

理过程中,使得B对象的状态也发生了改变,然后B来广播信息,然后A对象接到通知后,又触

发广播信息……,如此A引起B变化,B又引起A变化,从而一直相互广播信息,就造成死循环
了。

        观察者模式可能会引起无谓的操作,降低性能
   
由于观察者模式每次都是广播通信,不管观察者需不需要,每个观察者都会被调用update方

法,如果观察者不需要执行相应处理,那么这次操作就浪费了。

   增加了复杂度,容易引起误操作。死循环等。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics