设计模式之观察者模式

1. 什么是观察者模式?

   观察者模式即是(主题+观察者),当主题对象状态发生变化时,能将自身变化情况通知观察者,以至于观察者能做出相应的变化或者处理的设计模式。

主题和观察者关系如下图所示 :
图片来自书籍headfirsts设计模式

设计模式的使用场景?

项目中当对象间存在一对多关系时,则使用观察者模式(Observer Pattern),主要用于解决当一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。
2、需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

1 自定义观察者模式简单实现

package com.jun.interf;
/**
 * 主题接口
 * 所有主题实现类均要实现此接口
 * @author Administrator
 *
 */
public interface Subject {
/**
 * 注册观察者
 * @param observer
 */
public void registerObserver(Observer observer);
/**
 * 移除观察者
 * @param observer
 */
public void removeObserver(Observer observer);
/**
 * 通知所有观察者
 */
public void notifyObservers();
}

package com.jun.interfaceImpl;
import java.util.ArrayList;
import com.jun.interf.Observer;
import com.jun.interf.Subject;
/**
 * 主题实现类
 * @author Administrator
 *
 */
public class WeatherData implements Subject {
	//观察者容器
	private ArrayList<Observer>  observers;
	private float temp;
	private float humidity;
	private float pressure;
	@Override
	public void registerObserver(Observer observer) {
		// TODO Auto-generated method stub
		observers.add(observer);
	}

	@Override
	public void removeObserver(Observer observer) {
		// TODO Auto-generated method stub
		int indexOf = observers.indexOf(observer);
		if(indexOf!=-1)
		observers.remove(observer);
	}

	@Override
	public void notifyObservers() {
		// TODO Auto-generated method stub
		for(Observer observer:observers){
			observer.update(temp, humidity, pressure);
		}
	}
	/**
	 * 数据变化调用的方法
	 */
    public void msgChange(){
    	notifyObservers();	
    }
    /**
     * 执行业务逻辑代码
     */
    public void runBusinesTask(){
    	//通过API获取温度信息
    	//从数据库中获取温度信息判断数据是否变化
    	//其他业务逻辑处理
    	//通知观察者
    	msgChange();
    }
}

package com.jun.interf;
/**
 * 观察者
 * @author Administrator
 *  所有观察者均需要实现此接口
 */
public interface Observer {
/**
 * 更新方法
 * @param temp
 * @param humidity
 * @param pressure
 */
public void update(float temp,float humidity,float pressure);
}
package com.jun.interf;
/**
 * 显示模板
 * @author Administrator
 *
 */
public interface DisplayElement {
  /**
   * 显示布告
   */
	public void display();
}

package com.jun.interfaceImpl;

import com.jun.interf.DisplayElement;
import com.jun.interf.Observer;
import com.jun.interf.Subject;
/**
 1. 状况布告板实现
 2. @author Administrator
 3.  */
public class CurrentConditionsDisplay implements Observer,DisplayElement{
	private float temp;
	private float humidity;
	private float pressure;
	private Subject subject;
	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("==========temp:"+this.temp+"==humidity:"+this.humidity+"====pressure:"+this.pressure);
	}
	/**
	 * 我们创建出来的观察者实现类
	 * 需要注册到主题才能收到主题通知
	 * @param subject
	 */
	public CurrentConditionsDisplay(Subject subject){
		this.subject=subject;
		//简单实例代码
		subject.registerObserver(this);
	}
	@Override
	public void update(float temp, float humidity, float pressure) {
		// TODO Auto-generated method stub
		this.pressure=pressure;
		this.temp=temp;
		this.humidity=humidity;
	}
}
 *

z

3 JDK自带观察者模式实现

在java.util包下有主题类Observable类和观察者接口Observer,源代码如下

package java.util;

public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

package java.util;
public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    public Observable() {
        obs = new Vector<>();
    }
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        /*
         * a temporary array buffer, used as a snapshot of the state of
         * current Observers.
         */
        Object[] arrLocal;

        synchronized (this) {
            /* We don't want the Observer doing callbacks into
             * arbitrary code while holding its own Monitor.
             * The code where we extract each Observable from
             * the Vector and store the state of the Observer
             * needs synchronization, but notifying observers
             * does not (should not).  The worst result of any
             * potential race-condition here is that:
             * 1) a newly-added Observer will miss a
             *   notification in progress
             * 2) a recently unregistered Observer will be
             *   wrongly notified when it doesn't care
             */
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
    protected synchronized void setChanged() {
        changed = true;
    }

    /**
     * Indicates that this object has no longer changed, or that it has
     * already notified all of its observers of its most recent change,
     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
     * This method is called automatically by the
     * <code>notifyObservers</code> methods.
     *
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     */
    protected synchronized void clearChanged() {
        changed = false;
    }

    /**
     * Tests if this object has changed.
     *
     * @return  <code>true</code> if and only if the <code>setChanged</code>
     *          method has been called more recently than the
     *          <code>clearChanged</code> method on this object;
     *          <code>false</code> otherwise.
     * @see     java.util.Observable#clearChanged()
     * @see     java.util.Observable#setChanged()
     */
    public synchronized boolean hasChanged() {
        return changed;
    }

    /**
     * Returns the number of observers of this <tt>Observable</tt> object.
     *
     * @return  the number of observers of this object.
     */
    public synchronized int countObservers() {
        return obs.size();
    }
}

如上代码所示即是JDk自带的观察者模式实现类,当我们需要使用此方式实现观察者模式时,我们的自定义主题类需要继承Observable类,观察者需实现Observer接口即可使用观察者设计模式到具体应用中。
其中jdk还对主题对象数据的传递提供了两种方式,推(push)和拉(pull),当使用推方式调用主题的notifyObservers(Object arg)方法通知观察者,数据通过参数传递。
当使用拉时候使用notifyObservers()无参方式通知观察者。观察者通过主题的getxxx方法获取想要的数据值。

4 推(push)和拉(pull)两种方式的比较

推(push)会使得目标观察者收到多余无用的数据,但是其方式将主题对象的内部数据保护起来。观察者不知道主题的数据信息,扩展新的变化属性不方便。
拉(pull)的方式通过主题提供的getXxx方式获取到观察者自己在意的数据,这样可以降低对传递数据的误会,但是通过getXxx方式暴露了主题的内部数据。因此在实际使用中可衡量利弊选择对应的方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值