/** * 模拟 观察者模式 * 场景: * 小孩睡觉,家长工作 * 小孩醒来,家长喂饭 */ public class ObserverDemo01 { public static void main(String[] args) throws InterruptedException { MyBaby b = new MyBaby(); MyParent p1 = new MyParent("爸爸"); MyParent p2 = new MyParent("妈妈"); MyParent p3 = new MyParent("姥姥"); MyParent p4 = new MyParent("奶奶"); b.addObserver(p1); b.addObserver(p2); b.addObserver(p3); b.addObserver(p4); for(int i=0;i<5;i++){ Thread.sleep(1000); if(b.isAwake()){ b.sleep(); }else{ b.wakeUp(); } } } } /** * 监听者 */ interface IMyObserver{ void update(MyObservable obs); } /** * 被监听者 */ class MyObservable{ protected List<IMyObserver> list = new ArrayList<IMyObserver>(); public void addObserver(IMyObserver obs){ list.add(obs); } public void removeObserver(IMyObserver obs){ list.add(obs); } public void notifyAllObservers(){ for (IMyObserver obs : list) { obs.update(this); } } } /** * 以下为监听者、被监听者实例 */ class MyBaby extends MyObservable{ private boolean isAwake = false; public boolean isAwake(){ return this.isAwake; } public void wakeUp(){ System.out.println("baby醒了"); this.isAwake = true; notifyAllObservers(); } public void sleep(){ System.out.println("baby睡了"); this.isAwake = false; notifyAllObservers(); } } class MyParent implements IMyObserver{ private String name; public MyParent(String name){ this.name = name; } @Override public void update(MyObservable obs) { if( ((MyBaby)obs).isAwake() ){ System.out.println("["+name+"]来喂饭"); }else{ System.out.println("["+name+"]去工作"); } } }
运行结果:
baby醒了 [爸爸]来喂饭 [妈妈]来喂饭 [姥姥]来喂饭 [奶奶]来喂饭 baby睡了 [爸爸]去工作 [妈妈]去工作 [姥姥]去工作 [奶奶]去工作 baby醒了 [爸爸]来喂饭 [妈妈]来喂饭 [姥姥]来喂饭 [奶奶]来喂饭 baby睡了 [爸爸]去工作 [妈妈]去工作 [姥姥]去工作 [奶奶]去工作 baby醒了 [爸爸]来喂饭 [妈妈]来喂饭 [姥姥]来喂饭 [奶奶]来喂饭
/** * 观察者模式(JDK提供了相应的工具类) * * 1、创建被观察者(baby)继承 java.util.Observable * 在需要观察的动作(方法)完成后调用setChanged()方法和notifyObservers()方法通知观察者 * 2、创建观察者(parent)继承 java.util.Observer 重写 update() 方法 * 3、创建双方实例并将 观察者 注册到 被观察者 中(addObserver()方法) * * 实现观察/广播效果,避免了使用线程实现带来的大量开销 * 观察者/被观察者之间的关系也容易维护 * * 注意: * 1、观察者实例销毁前要通过deleteObserver()方法从监听列表中删除掉 * 否则对象之间依然会保持引用关系 对象未销毁 广播依然有效 * 2、避免循环依赖(死循环) * 3、多线程下要小心 * * 应用场景: * 网络编程、AWT、Android */ public class ObserverDemo02 { public static void main(String[] args) throws InterruptedException { Baby b = new Baby(); Parent p1 = new Parent("爸爸"); Parent p2 = new Parent("妈妈"); Parent p3 = new Parent("姥姥"); Parent p4 = new Parent("奶奶"); b.addObserver(p1); b.addObserver(p2); b.addObserver(p3); b.addObserver(p4); for(int i=0;i<5;i++){ Thread.sleep(1000); if(b.isAwake()){ b.sleep(); }else{ b.wakeUp(); } } } } class Baby extends Observable{ private boolean isAwake = false; public boolean isAwake(){ return this.isAwake; } public void wakeUp(){ System.out.println("baby醒了"); this.isAwake = true; setChanged(); notifyObservers(); } public void sleep(){ System.out.println("baby睡了"); this.isAwake = false; setChanged(); notifyObservers(); } } class Parent implements Observer{ private String name; public Parent(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { if( ((Baby)o).isAwake() ){ System.out.println("["+name+"]来喂饭"); }else{ System.out.println("["+name+"]去工作"); } } }
运行结果(同上):
baby醒了 [奶奶]来喂饭 [姥姥]来喂饭 [妈妈]来喂饭 [爸爸]来喂饭 baby睡了 [奶奶]去工作 [姥姥]去工作 [妈妈]去工作 [爸爸]去工作 baby醒了 [奶奶]来喂饭 [姥姥]来喂饭 [妈妈]来喂饭 [爸爸]来喂饭 baby睡了 [奶奶]去工作 [姥姥]去工作 [妈妈]去工作 [爸爸]去工作 baby醒了 [奶奶]来喂饭 [姥姥]来喂饭 [妈妈]来喂饭 [爸爸]来喂饭
/** * 妈妈,他拿咱裤子了 * 谁呀 * 逗你玩 */ public class ObserverDemo03 { public static void main(String[] args) throws InterruptedException { String[] arr = {"褂子","裤子","褥单子"}; YiJia yijia = new YiJia(arr); XiaoTou dnw = new XiaoTou("逗你玩",yijia); XiaoHu hu = new XiaoHu(); yijia.addObserver(hu); for(int i=0;i<arr.length;i++){ dnw.tou(); Thread.sleep(1000); } } } /** * 晾衣架 */ class YiJia extends Observable{ private int initSize; private String[] arr; public YiJia(String[] arr){ this.arr = arr; this.initSize = arr.length; } public int getInitSize(){ return initSize; } public void get(XiaoTou xt){ int index = arr.length-1; String oldVal = arr[index]; System.out.println("====["+xt.name+"]拿走了["+oldVal+"]"); xt.hold = oldVal; String[] newArr = new String[index]; System.arraycopy(arr, 0, newArr, 0, index); arr = newArr; setChanged(); notifyObservers(xt); } } /** * 小偷(逗你玩) */ class XiaoTou{ private YiJia yijia; String name; String hold; public XiaoTou(String name, YiJia yijia){ this.name = name; this.yijia = yijia; } public void tou(){ yijia.get(this); } } /** * 小虎 */ class XiaoHu implements Observer{ @Override public void update(Observable o, Object arg) { if(arg instanceof XiaoTou){ System.out.println("妈妈,他那咱*"+((XiaoTou)arg).hold+"*了!"); System.out.println("谁呀?"); System.out.println(((XiaoTou)arg).name); } } }
运行结果:
====[逗你玩]拿走了[褥单子] 妈妈,他那咱*褥单子*了! 谁呀? 逗你玩 ====[逗你玩]拿走了[裤子] 妈妈,他那咱*裤子*了! 谁呀? 逗你玩 ====[逗你玩]拿走了[褂子] 妈妈,他那咱*褂子*了! 谁呀? 逗你玩