观察者模式

观察者模式又名发布-订阅模式,定义了对象之间的一对多依赖,多个对象同时监听一个对象,当被监听对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新,被监听对象称为主题suject,监听对象称为观察者observer。

观察者模式结构如下(网上找的图):

观察者模式

简单来说,observer必须实现update方法,来接收suject状态变化时的通知及更新。suject维护一个observer列表,在状态变化时会逐个的调用observer的update方法来通知、更新observer,为此,suject须提供注册(添加observer到列表)、删除、通知更新三个方法。

观察者模式又分为两种模式:push和pull。push是指suject在状态变化时将所有的状态信息都发给observer,pull则是suject通知observer更新时,observer获取自己感兴趣的状态。

两种模式在实现上的区别:push模式下,observer的update方法接收的是状态信息,而pull模式下,update方法接收的是suject对象,这种情况下,suject须提供状态信息的get方法,让observer可以获取自己感兴趣的信息。

两种模式的优劣:push模式要求suject必须了解observer需要的状态,pull则是observer按需获取;push模式下observer的update方法的参数是具体的状态信息,发生变化时必须要重写update方法,pull模式则是将suject对象本身传给update,是最大的参数集合。

push模式具体实现:

  • suject超类
    package observer.push;
    
    import java.util.LinkedList;
    import java.util.List;
    
    /**
     * 推模式主题超类,能够注册、删除、数据变动时通知关注者
     * @author sky
     *
     */
    public abstract class Subject {
    	/**
    	 * 观察者名单
    	 */
    	private List<Observer> list = new LinkedList<>();
    	/**
    	 * 注册观察者
    	 * @param o 观察者
    	 */
    	public void addObserver(Observer o){
    		list.add(o);
    	}
    	/**
    	 * 删除观察者
    	 * @param o 观察者
    	 */
    	public void deleteObserver(Observer o){
    		int i = list.indexOf(o);
    		if (i>-1) {
    			list.remove(i);
    		}
    	}
    	/**
    	 * 通知观察者
    	 */
    	public void notifyObservers(String state){
    		for (Observer o:list) {
    			o.update(state);
    		}
    	}
    }
    
  • observer接口
    package observer.push;
    /**
     * 推模式观察者接口
     * @author sky
     *
     */
    public interface Observer {
    	
    	public void update(String state);
    
    }
    
  • suject具体实现类
    package observer.push;
    
    public class ConcreteSubject extends Subject {
    	/**
    	 * 状态
    	 */
    	public String state;
    	/**
    	 * 状态是否改变的标志
    	 */
    	public boolean isChanged = false;
    	
    	/**
    	 * 状态改变后,通知观察者
    	 */
    	public void change(){
    		if (isChanged) {
    			this.notifyObservers(state);
    		}
    	}
    
    	public String getState() {
    		return state;
    	}
    
    	public void setState(String state) {
    		this.state = state;
    		isChanged = true;
    	}
    
    	public boolean isChanged() {
    		return isChanged;
    	}
    
    	public void setChanged(boolean isChanged) {
    		this.isChanged = isChanged;
    	}
    	
    	
    
    }
    


  • observ具体实现类
    package observer.push;
    /**
     * 推模式观察者实现类
     * @author sky
     *
     */
    public class ConcreteObserver implements Observer {
    	
    	public String name;
    	
    	public ConcreteObserver(String n){
    		name=n;
    	}
    
    	@Override
    	public void update(String state) {
    		System.out.println(name+" update new state:"+state);
    		
    	}
    
    }
    
  • 测试类:
    package observer.push;
    
    public class Test {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		ConcreteSubject subject = new ConcreteSubject();
    		Observer o1 = new ConcreteObserver("张山");
    		Observer o2 = new ConcreteObserver("李四");
    		subject.addObserver(o1);
    		subject.addObserver(o2);
    		System.out.println("准备:");
    		subject.setState("上班了");
    		subject.change();
    		subject.setState("下班了");
    		subject.change();
    	}
    
    }
    

  • 输出:
    准备:
    张山 update new state:上班了
    李四 update new state:上班了
    张山 update new state:下班了
    李四 update new state:下班了

pull模式实现:

  • suject超类
    package observer.pull;
    
    import java.util.LinkedList;
    import java.util.List;
    
    /**
     * 拉模式主题超类,能够注册、删除、数据变动时通知关注者
     * @author sky
     *
     */
    public abstract class Subject {
    	/**
    	 * 观察者名单
    	 */
    	private List<Observer> list = new LinkedList<>();
    	/**
    	 * 注册观察者
    	 * @param o 观察者
    	 */
    	public void addObserver(Observer o){
    		list.add(o);
    	}
    	/**
    	 * 删除观察者
    	 * @param o 观察者
    	 */
    	public void deleteObserver(Observer o){
    		int i = list.indexOf(o);
    		if (i>-1) {
    			list.remove(i);
    		}
    	}
    	/**
    	 * 通知观察者
    	 */
    	public void notifyObservers(){
    		for (Observer o:list) {
    			o.update(this);
    		}
    	}
    }
    


  • observer接口
    package observer.pull;
    /**
     * 拉模式观察者接口
     * @author sky
     *
     */
    public interface Observer {
    	
    	public void update(Subject s);
    
    }
    


  • suject具体实现类
    package observer.pull;
    
    public class ConcreteSubject extends Subject {
    	/**
    	 * 状态
    	 */
    	public String state;
    	/**
    	 * 状态是否改变的标志
    	 */
    	public boolean isChanged = false;
    	
    	/**
    	 * 状态改变后,通知观察者
    	 */
    	public void change(){
    		if (isChanged) {
    			this.notifyObservers();
    		}
    	}
    
    	public String getState() {
    		return state;
    	}
    
    	public void setState(String state) {
    		this.state = state;
    		isChanged = true;
    	}
    
    	public boolean isChanged() {
    		return isChanged;
    	}
    
    	public void setChanged(boolean isChanged) {
    		this.isChanged = isChanged;
    	}
    	
    	
    
    }
    


  • observer具体实现类
    package observer.pull;
    /**
     * 拉模式观察者实现类
     * @author sky
     *
     */
    public class ConcreteObserver implements Observer {
    	
    	public String name;
    	
    	public ConcreteObserver(String n){
    		name=n;
    	}
    
    	@Override
    	public void update(Subject s) {
    		String state = ((ConcreteSubject)s).getState();
    		System.out.println(name+" update new state:"+state);
    		
    	}
    
    
    }
    


  • 测试类
    package observer.pull;
    
    public class Test {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		ConcreteSubject subject = new ConcreteSubject();
    		Observer o1 = new ConcreteObserver("张山");
    		Observer o2 = new ConcreteObserver("李四");
    		subject.addObserver(o1);
    		subject.addObserver(o2);
    		System.out.println("pull模式准备:");
    		subject.setState("上班了");
    		subject.change();
    		subject.setState("下班了");
    		subject.change();
    	}
    
    }
    


  • 输出
    pull模式准备:
    张山 update new state:上班了
    李四 update new state:上班了
    张山 update new state:下班了
    李四 update new state:下班了