观察者模式

观察者模式

    定义对象之间的一对多(包含一对一)的依赖关系,当一方对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新


   在Subject(目标对象)中,维护了一个观察者的列表,通过attach(Observer o) 添加观察者,detach(Observer o)删除观察者,并通过Notify()方法通知所有的观察者进行更新

   这里给一个具体的案例,方便理解。我的朋友小明在天气局工作,为了讨好她的女朋友和老妈,它决定给他们推送最及时最新的天气情况。这里可以用到观察者模式


拉模型的通用代码:将目标对象本身作为参数传递到观察者中,当观察者需要某些信息时主动到目标对象中去拉数据

public class Subject
{
	private List<Observer> observers = new ArrayList<Observer>();
	
	public void attach(Observer observer)
	{
		observers.add(observer);
	}
	
	public void detach(Observer observer)
	{
		observers.remove(observer);
	}
	
	public void notifyObserver()  //没有参数
	{
		for (Observer observer : observers)
		{
			observer.update(this); //调用观察者的update方法,并将当前对象作为参数传递过去(拉模式)
		}
	}
}
/**
 * 具体的目标对象,负责把有关状态存到相应的观察者对象中
 * @author Administrator
 *
 */
public class ConcreteSubject extends Subject
{
	//目标对象的状态
	private String subjectState;
    
	public String getSubjectState() {
		return subjectState;
	}

	public void setSubjectState(String subjectState) {
		this.subjectState = subjectState;
		this.notifyObserver();   //当更新目标对象的状态信息时, 进行广播通知
	}
}
/**
 * 这是一个观察者的接口,定义一个更新接口给那些在目标状态发生改变时被通知的对象
 * @author Administrator
 *
 */
public interface Observer
{
	//观察者对象的更新方法,传入目标对象,方便获取相应的目标对象的状态信息
	public void update(Subject subject);
}
/*
 *具体的观察者实现类,实现观察者自身的更新
 */
public class ConcreteObserver implements Observer
{
	//观察者状态,与目标对象的状态保持一致
	private String observerState;
	private String observerName;

	/**
	 * 获取目标类的状态同步到观察者的状态中
	 */
	@Override
	public void update(Subject subject)   //按需取内容
	{
		observerState = ((ConcreteSubject)subject).getSubjectState();
        //...根据获取到的目标对象的状态信息,进行相应的更新操作
		System.out.println("收到天气通知的人为:"+ observerName+"  此时的天气信息是:"+observerState);
	}

	public String getObserverName() {
		return observerName;
	}

	public void setObserverName(String observerName) {
		this.observerName = observerName;
	}

}
/*
 * 测试方法,典型的推模式
 */
public class test
{
	public static void main(String[] args)
	{
		ConcreteSubject subject = new ConcreteSubject();
		ConcreteObserver observer1 = new ConcreteObserver();
		observer1.setObserverName("小明的女朋友");
		
		ConcreteObserver observer2 = new ConcreteObserver();
		observer2.setObserverName("小明的老妈");
		
		subject.attach(observer1);
		subject.attach(observer2);
        
		subject.setSubjectState("天气晴");
	}
}

推模型:目标对象只想观察者对象中推送部分有用的信息,观察者无法获得为推送的信息

public void update(String message);

@Override
public void update(String message)   //按需取内容
{
<span style="white-space:pre">	</span>observerState = message;
<span style="white-space:pre">	</span>//observerState = ((ConcreteSubject)subject).getSubjectState();
       //...根据获取到的目标对象的状态信息,进行相应的更新操作
<span style="white-space:pre">	</span>System.out.println("收到天气通知的人为:"+ observerName+"  此时的天气信息是:"+observerState);
}


public void notifyObserver(String message)  //没有参数
{
<span style="white-space:pre">	</span>for (Observer observer : observers)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>observer.update(message); //调用观察者的update方法,并将当前对象作为参数传递过去(拉模式)
<span style="white-space:pre">	</span>}
}


public void setSubjectState(String subjectState) {
<span style="white-space:pre">	</span>this.subjectState = subjectState;
<span style="white-space:pre">	</span>this.notifyObserver(subjectState);   //当更新目标对象的状态信息时, 进行广播通知
}



利用java提供的观察者实现

//目标类,实现java的Observable
public class ConcreteSubject extends Observable
{
	//要推送的信息
    private String message;
	
	public void setMessage(String message) {
		this.message = message;
		//通知之前的必要步骤
		this.setChanged();
		this.notifyObservers();  //拉模型,会以目标对象自身作为参数,值传递目标对象
		//this.notifyObservers(message); //推模型,只推送部分需要的信息,会同时把该目标对象传递过去
	}
    
	public String getMessage() {
		return message;
	}
}
public class ConcreteObserver implements Observer {

	private String name;
	@Override
	public void update(Observable o, Object arg) {
		System.out.println("收到信息的观察者是:"+name+"  收到的信息是"+arg);
		
		System.out.println("收到信息的观察者是:"+name+"  收到的信息主动到目标对象中取拉:"+ ((ConcreteSubject)o).getMessage());
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
    
}
/*
 * 测试方法,同时实现推拉
 */
public class test
{
	public static void main(String[] args)
	{
		ConcreteSubject subject = new ConcreteSubject();
		ConcreteObserver observer1 = new ConcreteObserver();
		observer1.setName("小明的女朋友");
		
		ConcreteObserver observer2 = new ConcreteObserver();
		observer2.setName("小明的老妈");
		
		subject.addObserver(observer1);
		subject.addObserver(observer2);
        
		subject.setMessage("今天下雨");
	}
}

观察者模式优缺点 (触发联动)

1>实现了观察者与目标之间的抽象耦合

2>实现了动态联动

3>支持广播通信

4>可能会引起无谓的操作


何时使用观察者模式:

1>当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化

2>如果在更改一个对象时,需要同时连带改变其他的对象,而且不知道究竟有多少需要被连带改变

3>当一个对象必须通知其他的对象,但是又希望这个对象和其他的对象之间松散耦合


如果不同的目标对象的更新信息需要通知不同的和观察者,则在Subject中定义抽象notify()方法,具体实现留到其子类中,根据不同的观察者以及不同的信息进行通知.。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值