`
巴赫的梦幻
  • 浏览: 73861 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

观察者模式

 
阅读更多
观察者模式在JDK中有了很好的支持,目前,开发者使用JDK提供的观察者模式有两种途径。
1. 被观察者继承Observerable父类;观察者实现Oberver接口。
2. 在EventObject中封装消息参数;然后,在EventListenr中实现监听者(观察者)的动作。

首先来看采用Observable实现的观察者模式。
在这个例子中,我们将以“北朝鲜”作为一个被观察者,而北朝鲜的一举一动都影响的着半岛的稳定。而中美作为世界的两个大国,更是时刻关注者北朝鲜的一举一动。因此,中国和美国,各自都是观察者。而北朝鲜的关注点,无非是“原子弹”和“金正日同志的健康”。因此,如果,朝鲜宣布,核爆成功,那么,这两个观察者就会分别发表声明;如果,金正日死了,那么,两个观察者在观察到这个消息之后,也会做出不同的表态。

封装了半岛局势的枚举:
/**
 * 朝鲜半岛的关注点。
 * 
 * @author hongxin.xu
 * @version $Id: PeninsulaEnum.java, v 0.1 2012-1-2 下午3:46:10 hongxin.xu Exp $
 */
public enum PeninsulaEnum {

    /** 试爆成功。 */
    NUCLEAR,

    /** 金哥Bye! */
    KIMJIONIIDEAD;

}


被观察者(北朝鲜的实例),这里需要注意的是,被观察者,必须要继承Observable父类。该父类中提供了“添加监听器”、“删除监听器”、“触发监听器”的方法。注意,在触发监听器操作之前,必须设置变更状态。否则,监听器将不会被触发。
/**
 * 被观察者的实例。
 * <p>
 * 伟大的北朝鲜政权,是世界各国关注的焦点。 因此,在这里将其作为一个被观察者的实例。
 * </p>
 * 
 * @author hongxin.xu
 * @version $Id: ChinaObserver.java, v 0.1 2012-1-2 下午3:14:53 hongxin.xu Exp $
 */
public class NorthKoreaSubject extends Observable {
	public static void main(String[] args) {
		// 声明两个观察者。
		Observer china = new ChinaObserver();
		Observer american = new AmericanObserver();

		// 添加观察者
		NorthKoreaSubject northKoreaSubject = new NorthKoreaSubject();
		northKoreaSubject.addObserver(china);
		northKoreaSubject.addObserver(american);

		// 触发事件。
		System.out.println("Kim-Jong-II:我们有原子弹了思密达!");
		northKoreaSubject.setPeninsulaEnum(PeninsulaEnum.NUCLEAR);

		// 触发事件。
		System.out.println("Kim-Jong-II:我挂了~~~");
		northKoreaSubject.setPeninsulaEnum(PeninsulaEnum.KIMJIONIIDEAD);

	}

	/**
	 * @param peninsulaEnum
	 *            the peninsulaEnum to set
	 */
	public void setPeninsulaEnum(PeninsulaEnum peninsulaEnum) {
		// 设置状态位。
		super.setChanged();

		// 触发notify事件。
		super.notifyObservers(peninsulaEnum);
	}
}


下面给出两个观察者的实例:
1.中国
/**
 * 中国作为一个观察者,时时刻刻关注着北朝鲜的动态。
 * 
 * @author hongxin.xu
 * @version $Id: ChinaObserver.java, v 0.1 2012-1-2 下午3:19:39 hongxin.xu Exp $
 */
public class ChinaObserver implements Observer {

    /**
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof PeninsulaEnum) {
            PeninsulaEnum msg = (PeninsulaEnum) arg;
            if (msg == PeninsulaEnum.KIMJIONIIDEAD) {
                System.out.println("  --中国外交部发来唁电");
            }
            if (msg == PeninsulaEnum.NUCLEAR) {
                System.out.println("  --中国外交部表示谴责!");
            }
        }
    }

}


2.美国
public class AmericanObserver implements Observer {

    /**
     * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
     */
    @Override
    public void update(Observable o, Object arg) {
        if (arg instanceof PeninsulaEnum) {
            PeninsulaEnum msg = (PeninsulaEnum) arg;
            if (msg == PeninsulaEnum.KIMJIONIIDEAD) {
                System.out.println("  --白宫表示毫无压力");
            }
            if (msg == PeninsulaEnum.NUCLEAR) {
                System.out.println("  --白宫很生气,后果很严重");
            }
        }
    }

}


至此,我们就利用Observable实现了一个观察者模式。其运行的结果为:
Kim-Jong-II:我们有核原子弹了思密达!
  --白宫很生气,后果很严重
  --中国外交部表示谴责!
Kim-Jong-II:我挂了~~~
  --白宫表示毫无压力
  --中国外交部发来唁电


以上是采用Observer/Observerable实现的观察者模式。在JDK中还有另外的一种,实现观察者模式的方法,那就是使用EventObject和EventListener。还是采用“北朝鲜”的例子,我们来进行说明:
首先,定义半岛局势的枚举
/**
 * 定义半岛局势的枚举
 * 
 * @author ibm
 * 
 */
public enum PeninsulaEnum {
	UNCLEAN, KIMJIONIIDEAD;
}


然后,在PeninsulaSituation中封装对该枚举的引用。同时,实现的状态的设置。
/**
 * 半岛局势实例。
 * 
 * @author ibm
 * 
 */
public class PeninsulaSituation extends EventObject {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/** 半岛枚举。 */
	private PeninsulaEnum peninsulaEnum;

	public PeninsulaSituation(Object source) {
		super(source);
		// TODO Auto-generated constructor stub
		if (source instanceof PeninsulaEnum) {
			peninsulaEnum = (PeninsulaEnum) source;
		}
	}

	/**
	 * @return the peninsulaEnum
	 */
	public PeninsulaEnum getPeninsulaEnum() {
		return peninsulaEnum;
	}

	/**
	 * @param peninsulaEnum
	 *            the peninsulaEnum to set
	 */
	public void setPeninsulaEnum(PeninsulaEnum peninsulaEnum) {
		this.peninsulaEnum = peninsulaEnum;
	}

}


与采用Observer的方式不同,如果使用EventListener来进行观察。那么,就必须自己来实现观察者的管理和触发。因此,这里给出如下的观察者的实现:
/**
 * 被观察者实例。
 * 
 * @author ibm
 * 
 */
public class NorthKoreaSubject {
	/** 保存观察者实例的容器。 */
	private final Vector repo = new Vector();

	/**
	 * 添加事件监听器。
	 * 
	 * @param eventListener
	 */
	public synchronized void addEventListener(EventListener eventListener) {
		repo.addElement(eventListener);
	}

	public void notifyListener(EventObject e) throws IllegalAccessException {
		Object[] localArr;

		if (repo == null) {
			throw new IllegalAccessException("Vector is empty");
		}

		synchronized (this) {
			if (!repo.isEmpty()) {
				localArr = repo.toArray();
				for (Object element : localArr) {
					((GovernmentListener) element).handler(e);
				}
			}
		}
	}
}


至此,被观察者的实现完成了。下面对观察者的实现进行介绍。首先,EventListener是一个没有任何方法的标识接口,为了能够表示观察者需要统一完成的动作,我们需要自定出一个接口,该接口继承自EventListener接口。
/**
 * 监听器实例。
 * 
 * @author ibm
 * 
 */
public interface GovernmentListener extends EventListener {
	/** 接口中包含了事件对象。 */
	void handler(EventObject e);
}


同样,中国和美国分别是这两个接口的实现。
/**
 * 监听器的实现,中国。
 * @author ibm
 *
 */
public class ChinaEventListener implements GovernmentListener {

	@Override
	public void handler(EventObject e) {
		// TODO Auto-generated method stub
		if (e instanceof PeninsulaSituation) {
			PeninsulaEnum situation = ((PeninsulaSituation) e)
					.getPeninsulaEnum();
			if (situation == PeninsulaEnum.KIMJIONIIDEAD) {
				System.out.println("  --中国外交部发来唁电");
			}
			if (situation == PeninsulaEnum.UNCLEAN) {
				System.out.println("  --中国外交部表示谴责");
			}
		}
	}

}


/**
 * 监听器的实现,美国。
 * 
 * @author ibm
 * 
 */
public class AmericanEventListener implements GovernmentListener {

	@Override
	public void handler(EventObject e) {
		// TODO Auto-generated method stub
		if (e instanceof PeninsulaSituation) {
			PeninsulaEnum situation = ((PeninsulaSituation) e)
					.getPeninsulaEnum();
			if (situation == PeninsulaEnum.KIMJIONIIDEAD) {
				System.out.println("  --白宫表示毫无压力");
			}
			if (situation == PeninsulaEnum.UNCLEAN) {
				System.out.println("  --白宫很生气,后果很严重");
			}
		}
	}

}


下面是测试类
/**
 * 事件监听器启动实例。
 * 
 * @author ibm
 * 
 */
public class EventListenerStartDemo {
	private final static NorthKoreaSubject subject = new NorthKoreaSubject();

	public static void main(String[] args) {

		try {
			EventListener china = new ChinaEventListener();
			EventListener american = new AmericanEventListener();

			subject.addEventListener(china);
			subject.addEventListener(american);

			EventObject event1 = new PeninsulaSituation(
					PeninsulaEnum.KIMJIONIIDEAD);
			EventObject event2 = new PeninsulaSituation(PeninsulaEnum.UNCLEAN);

			System.out.println("Kim Jong II -- 我挂了");
			subject.notifyListener(event1);

			System.out.println("Kim Jong II -- 我们有原子弹了思密达");
			subject.notifyListener(event2);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}


其执行的结果是:
Kim-Jong-II:我们有核原子弹了思密达!
  --白宫很生气,后果很严重
  --中国外交部表示谴责!
Kim-Jong-II:我挂了~~~
  --白宫表示毫无压力
  --中国外交部发来唁电


以上是放假,闲来无事自娱自乐的一些整理,希望大家拍砖!
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics