Observer——观察者模式

一、定义

      观察者模式在GOF上是这么定义的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种对象间的交互也叫发布-订阅。

二、场景设计

      考虑这样一种应用场景:一组数据实时动态变化,现在要对这组数据进行可视化表示。表示形式可能又很多:柱状图,表格,饼状图等。数据的变化要及时反映在可视化的表示中。这就是典型的发布-订阅场景,各种可视化形式要观察着数据的状态。一旦数据发生变化,变化要传递给各个正在观察的可视化表示形式。

      同时,要注意到可视化表示形式可能有多个,数据不应该对哪些观察者正在观察做出任何的假设。这里将维护数据的类称为ConcreteSubject,将各个作为观察者的可视化形式的类称为ConcreteObserver,ConcreteObserver可能有多种类型。基于面向对象的设计原则来考虑:将变化的和不变的分离出来。可以抽象出一个Observer类,该类中维护Update()虚方法,在这个例子中,该方法代表各个可视化形式的更新方式。通过这个抽象,可以向被观察者(数据)屏蔽观察者的具体信息。

      这样抽象之后,可以在ConcreteSubject类中维护一个Observer类的链表,当有一个ConcreteObserver开始观察数据时,首先要注册到这个链表中。这样当ConcreteSubject状态发生改变后,可以通过遍历这个链表来向所有注册的观察者发布相应变化。

      至此,发布-订阅功能已经能实现了。但是,若是被观察者有多个,即ConcreteSubject有多种类型,那这套设计就显得不灵活了。这里可以对ConcreteSubject进行一层抽象。抽象出Subject类,这个类维护Observer类链表中元素的增加,删除以及状态变化后的遍历广播。而被观察者的状态改变方法Set()和状态获取方法Get(),自然由具体类ConcreteSubject各自来维护。在这种情况下,要扩展Observer类中的Update接口,以使得观察者知道通知是由哪个被观察者送来。被观察者可以简单将自己作为Update操作的一个参数,让观察者知道该去检查哪个目标。


三、代码实现

Observer接口:

public interface Observer {
	
	  void update(String state);
	  void update(Subject subject);
}
这里重载了两个update函数,一个以Subject的变化属性为参数,用以实现 推协议;另一个以Subject本身为参数,用以实现 拉协议。

Subject虚类:

import java.util.*;
public abstract class Subject {
	private List<Observer> list=new ArrayList<Observer>();
	
	public void attach(Observer ob)
	{
		list.add(ob);
		System.out.println("Attach an observer");
	}
	
	public void detach(Observer ob)
	{
		list.remove(ob);
		System.out.println("Remove an observer");
	}
	
	public void notifyObservers(String newstate)
	{
		 for(Observer temp:list)
		 {
			 temp.update(newstate);
		 }
	}
	
	public void notifyObservers()
	{
		for(Observer temp:list)
			temp.update(this);
	}
}

同样的,notifyObservers也重载了两个,一个以new state为参数;另一个无参数,但是调用observer的update时,将自身传递过去,由Observer决定是否对变化做出响应。

ConcreteObserver类:

public class ConcreteObserver implements Observer{
	
	private String observerState;
	private int observerInt;
	public void update(String newstate)
	{
		observerState=newstate;
		System.out.println("状态变化,推送:"+observerState);
	}
	
	public void update(Subject subject)
	{
		observerInt=((ConcreteSubject)subject).getNum();
		System.out.println("状态变化,拉到:"+observerInt);
	}

}

这里要注意以Subject对象为参数的update方法。其中使用了向下造型,这样可以得到实际传递进来的ConcreteSubject的对象,再决定对哪些变化的值做出处理。这就是 拉协议

的关键所在

ConcreteSubject类:

public class ConcreteSubject extends Subject{
	
	private String state;
	private int num;
	public String getState()
	{
		return this.state;
	}
	public int getNum()
	{
		return this.num;
	}
	public void change(String newstate)
	{
		state=newstate;
		
		System.out.println("状态变化:"+state);
		
		this.notifyObservers(newstate);
	}
	
	public void change(String newstate,int num)
	{
		this.state=newstate;
		this.num=num;
		System.out.println("状态变化:"+this.state+" "+this.num);
		this.notifyObservers();
	}
}

注意,change(String,int)改变的是state和num两个值,但是调用了无参数的notifyObservers(),这里被通知Observer只会显示num的改变。

Client类:

public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ConcreteSubject subject=new ConcreteSubject();
		
		Observer observer1=new ConcreteObserver();
		
		subject.attach(observer1);
		
		subject.change("I hate You",2);
		
		System.out.println("-----------------");
		
		Observer observer2=new ConcreteObserver();
		
		subject.attach(observer2);
		
		subject.change("I Love you");
	}

}

运行结果:

Attach an observer

状态变化:I hate You 2

状态变化,拉到:2

-----------------

Attach an observer

状态变化:I Love you

状态变化,推送:I Love you

状态变化,推送:I Love you


最后,Java中提供了对观察者模式的支持:java.util.Observer和java.util.Observable,可以好好研究下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值