设计模式之观察者模式

    观察者模式(Observer)定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象,当这个主题对象发生变化的时候,会通知所有的观察者对象,让他们主动更新自己。

    还是举个形象的例子:大学英语课的时候上听力课,一般在语音教室里面,每个人位子上都会有个耳机,这个耳机的通路都是老师可以控制的,老师先把所有的通路都打开(增加观察者)。学生都戴着耳机听着老师的口令做出对应的动作,老师让跟读就跟读(发出通知)。这里老师就可以当做是被观察者,学生(N个)就是观察者,这里一个很明显的一对多关系。当老师把某几个学生的通路切断之后,这些学生是听不到老师的口令,也就是说失去了对老师的观察(主题角色删除观察者角色),当老师再发出口令的时候他们就不会做出对应的反馈,因为收不到“通知”. 这个例子就是个非常形象的观察者模式原型,技术源于生活:-)

 观察者模式的组成:

-->抽象主题角色:把所有对观察者的引用保存在一个集合里面,每个抽象主题角色可以有任意数量的观察者,抽象主题提供一个接口,这个接口可以用来增加和删除观察者,一般用一个抽象类或者接口实现。

-->抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的时候更新自己。

-->具体主题角色:在主题角色内部内容发生改变的时候,给所有登记过的观察者发出通知,触发观察者做出相应的改变。

-->具体观察者角色:实现抽象观察者角色的接口内容,以便在收到主题角色的通知的时候做出相应的改变,从而达到与主体角色的协调,如果需要可以保存一个对主题角色的引用,通常用一个子类表示。

下面我们来实现一个自己的观察者模式:

主要就是按照上面四部分+一个测试客户端组成:

抽象主题角色:Watched.java


<span style="font-family:Microsoft YaHei;font-size:14px;">package com.java.obsevabelTest1;

public interface Watched {
       //这里的几个函数都是观察者模式所需要具备的
	public void addWatcher(Watcher w);//增加观察者
	public void removeWatcher(Watcher w);//删除观察者
	public void notifyWatchers(String str);//发出通知,这里的str是作为通知的参数传递出去的。
}
</span>

抽象观察者角色:Watcher.java

<span style="font-family:Microsoft YaHei;">package com.java.obsevabelTest1;

public interface Watcher {
	
	public void update(String str);//观察者收到通知更新消息

}</span>

具体主题角色:ConcerateWatched.java


<span style="font-family:Microsoft YaHei;">package com.java.obsevabelTest1;

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

public class ConcerateWatched implements Watched {

	List<Watcher> listWatcher = new ArrayList<Watcher>();//list结构,用于保存所有的观察者
	@Override
	public void addWatcher(Watcher w) {
		
		listWatcher.add(w);

	}

	@Override
	public void removeWatcher(Watcher w) {

		listWatcher.remove(w);
	}

	/**
	 * 这里的通知所有的观察者实际上是一个遍历list所有对象,对对象的update方法进行调用而已。
	 */
	@Override
	public void notifyWatchers(String str) {

		for(Watcher ws:listWatcher){
			ws.update(str);
		}
	}

}</span>

具体观察者角色:ConcerateWatcher.java


<span style="font-family:Microsoft YaHei;font-size:14px;">package com.java.obsevabelTest1;

public class ConcerateWatcher implements Watcher {

	@Override
	public void update(String str) {
		
		System.out.println("get Message: "+ str);//输出更新后的消息

	}

}
</span>
测试客户端:TestMain.java

<span style="font-family:Microsoft YaHei;font-size:14px;">package com.java.obsevabelTest1;

public class TestMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Watched cWatched =new ConcerateWatched();

		Watcher w1 = new ConcerateWatcher();
		Watcher w2 = new ConcerateWatcher();
		Watcher w3 = new ConcerateWatcher();
		
		cWatched.addWatcher(w1);
		cWatched.addWatcher(w2);
		cWatched.addWatcher(w3);
		
		cWatched.notifyWatchers("被观察者更新了!");
		
		cWatched.removeWatcher(w2);
		cWatched.notifyWatchers("移除一个又更新了!");
		
		
	}

}
</span>

输出结果:

get Message: 被观察者更新了!
get Message: 被观察者更新了!
get Message: 被观察者更新了!
get Message: 移除一个又更新了!
get Message: 移除一个又更新了!

上面的例子其实就是观察者模式的全部,相对来说还是比较简单的,观察者模式在实际运用中比较多,很重要,所以java对观察者模式在API中也提供了对应的接口。

Observabel类和Observer接口,其中Observabel就是被观察者,而接口Observer就是观察者接口。当深入到API中去查看源码的时候其实就会发现,这个类和接口的实现和我们上面的demo差不多的。不过这里有个差异就是当被观察者有变更的时候需要发出setchange的动作才能触发观察者“收到”通知。

例子:

这里采用java API中现成的类实现相应的观察者操作,定义了两个观察者当计数器达到5之后,将第二个观察者踢出去。

被观察者类:

ObservalCon.java

<span style="font-family:Microsoft YaHei;">package com.java.obsevabelTest1;

import java.util.Observable;

public class ObservalCon extends Observable {

	/**
	 * 这里封装的原因是setChanged是protect类型,继承类是直接调用不了的,内部封装下即可。其实也可以直接在main测试的那个
	 * 类中直接继承Observable的类。这样就可以直接this.setChanged()调用了。
	 */
	public void setChangeValue(){
		this.setChanged();
	}
}</span>

观察者类1.

ObservalClient.java

<span style="font-family:Microsoft YaHei;">package com.java.obsevabelTest1;

import java.util.Observable;
import java.util.Observer;

public class ObservalClient implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		
		System.out.println("obseral 1 get msg is :"+arg);

	}

}</span>


观察者类2.

ObservalClient2.java

<span style="font-family:Microsoft YaHei;font-size:14px;">package com.java.obsevabelTest1;

import java.util.Observable;
import java.util.Observer;

public class ObservalClient2 implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		
		System.out.println("obseral 2 get msg is :"+arg);

	}
	
	

}
</span>

测试客户端.

<span style="font-family:Microsoft YaHei;font-size:14px;">package com.java.obsevabelTest1;

import java.util.Observable;

public class TwoObservalMain {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		ObservalCon obCon = new ObservalCon();
		//Observable obCon = new Observable();
		
		ObservalClient obClient1 = new ObservalClient();
		ObservalClient2 obClient2 = new ObservalClient2();
		obCon.addObserver(obClient1);
		obCon.addObserver(obClient2);
		
		for(int i=0;i<10;i++){
		    obCon.setChangeValue();
			obCon.notifyObservers(i);
			if(i>=5){
				obCon.deleteObserver(obClient2);
			}
		}
	}

}</span><span style="font-size:14px;">
</span>

输出结果如下:

obseral 2 get msg is :0
obseral 1 get msg is :0
obseral 2 get msg is :1
obseral 1 get msg is :1
obseral 2 get msg is :2
obseral 1 get msg is :2
obseral 2 get msg is :3
obseral 1 get msg is :3
obseral 2 get msg is :4
obseral 1 get msg is :4
obseral 2 get msg is :5
obseral 1 get msg is :5
obseral 1 get msg is :6
obseral 1 get msg is :7
obseral 1 get msg is :8
obseral 1 get msg is :9

可以看到,从5输出之后,就只有1才能收到通知了,这里知道为啥是后从obseral2 然后再obseral 1呢?看源码去探索下:-)




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值