1、观察者模式的简单介绍:

a、核心:

-  观察者模式主要用于 1 : N 的通知中。当一个对象(目标对象 Subject 或者 Objservable )的状态变化时,他需要及时告知一系列的对象(观察者对象,Observer),令他们做出响应。

    

b、通知观察者的方式:

-  推:每次都会把通知以广播的方式发送给所有的观察者,所有的观察者只能够被动接收。

-  拉:观察者只要知道有情况即可。至于什么时候获取内容,获取什么内容,都可以自主决定。


2、简单的代码演示:

a、Subject 类为目标对象类(相当于一个容器,里面存放了一些的观察者对象),提供了在主题对象中注册观察者对象的方法。ConcreteSubject 为具体的主题对象,里面提供了一个 stateCode 的成员变量,并且在 setStateCode() 方法中使用父类的 notifyAllObserver() 方法。

package com.geeklicreed.observer;

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

public class Subject {
	protected List<Observer> list = new ArrayList<Observer>();
	
	public void registerObserver(Observer observer){
		list.add(observer);
	}
	
	public void removeObserver(Observer observer){
		list.remove(observer);
	}
	
	public void notifyAllObservers(){
		for(Observer observer: list){
			observer.update(this);
		}
	}
}
package com.geeklicreed.observer;

public class ConcreteSubject extends Subject{
	private int stateCode = 0;
	
	public int getStateCode(){
		return stateCode;
	}
	
	public void setStateCode(int stateCode){
		this.stateCode = stateCode;
		notifyAllObservers();
	}
}


b、创建 Observer 接口,即抽象的观察者类,并创建一个实现了该接口的 ConcreteObserver 类。(在该类中也有一个 stateCode 的成员变量)

package com.geeklicreed.observer;

public interface Observer {
	void update(Subject subject);
}
package com.geeklicreed.observer;

public class ConcreteObserver implements Observer{
	//状态码应该和主题对象保持一致
	private int stateCode = 0;
	
	public void update(Subject subject){
		stateCode = ((ConcreteSubject)subject).getStateCode();
	}
	
	public int getStateCode(){
		return stateCode;
	}

	public void setStateCode(int stateCode){
		this.stateCode = stateCode;
	}
}


c、看看 Client 测试类中的输出结果以及示例代码的类图关系。

package com.geeklicreed.observer;

public class Client {
	public static void main(String[] args) {
			ConcreteSubject concreteSubject = new ConcreteSubject();
			
			ConcreteObserver concreteObserver1 = new ConcreteObserver();
			ConcreteObserver concreteObserver2 = new ConcreteObserver();
			ConcreteObserver concreteObserver3 = new ConcreteObserver();
			
			concreteSubject.registerObserver(concreteObserver1);
			concreteSubject.registerObserver(concreteObserver2);
			concreteSubject.registerObserver(concreteObserver3);
			
			concreteSubject.setStateCode(1000);
			
			System.out.println("======================================");
			System.out.println(concreteObserver1.getStateCode());
			System.out.println(concreteObserver2.getStateCode());
			System.out.println(concreteObserver3.getStateCode());
			
			/*输出结果为:
			======================================
			1000
			1000
			1000*/
	}
}

设计模式之观察者模式_通知观察者的方式

3、使用 javase 提供的 java.util.Observable 和 java.util.Observer 来实现观察者模式:

-  Observable 类是目标类,Observer 接口是观察者接口,ConcreteSubject 是具体目标类,ConcreteObserver 是具体观察者类,使用 已经封装好的方法来实现我们的观察者模式。

package com.geeklicreed.observer;

import java.util.Observable;

public class ConcreteSubject extends Observable {
	private int stateCode;

	public void set(int state) {
		this.stateCode = state;
		setChanged();
		notifyObservers(state);
	}

	public int getStateCode() {
		return stateCode;
	}

	public void setStateCode(int stateCode) {
		this.stateCode = stateCode;
	}

}
package com.geeklicreed.observer;

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

public class ConcreteObserver implements Observer {
	// 状态码应该和主题对象保持一致
	private int stateCode;

	public int getStateCode() {
		return stateCode;
	}

	public void setStateCode(int stateCode) {
		this.stateCode = stateCode;
	}

	@Override
	public void update(Observable o, Object arg) {
		this.stateCode = ((ConcreteSubject)o).getStateCode();
	}

}
package com.geeklicreed.observer;

public class Client {
	public static void main(String[] args) {
			ConcreteSubject concreteSubject = new ConcreteSubject();
			
			ConcreteObserver concreteObserver1 = new ConcreteObserver();
			ConcreteObserver concreteObserver2 = new ConcreteObserver();
			ConcreteObserver concreteObserver3 = new ConcreteObserver();
			
			concreteSubject.addObserver(concreteObserver1);
			concreteSubject.addObserver(concreteObserver2);
			concreteSubject.addObserver(concreteObserver3);
			
			concreteSubject.set(1000);
			
			System.out.println("======================================");
			System.out.println(concreteObserver1.getStateCode());
			System.out.println(concreteObserver2.getStateCode());
			System.out.println(concreteObserver3.getStateCode());
			
			/*输出结果为:
			======================================
			1000
			1000
			1000*/
	}
}


4、开发中常见的场景:

-  聊天室程序的,服务器转发给所有客户端

-  网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发

-  邮件订阅

-  Servlet 中,监听器的实现

-  Android 中,广播机制

-  京东商城中,群发某商品的打折信息