观察者模式又称为发布订阅模式:多个对象同时观察一个对象,一个对象的改变引起多个对象的改变
定义被观察者:
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. * 定义被观察者接口 */ public interface Observable { /** * 添加观察者 * @param observer */ void addObserver(Observer observer); /** * 移除观察者 * @param observer */ void removeObserver(Observer observer); /** * 通知所有观察者内容 * @param content 通知内容 */ void notifyObservers(String content); }
定义被观察者统一实现父类:
package com.whereta.observer; import java.util.ArrayList; import java.util.List; /** * Vincent 创建于 2016/5/3. * 被观察者统一的父类对象 */ public class Subject implements Observable { private final List<Observer> observerList=new ArrayList<Observer>(); public void addObserver(Observer observer) { observerList.add(observer); } public void removeObserver(Observer observer) { observerList.remove(observer); } public void notifyObservers(String content) { for(Observer observer:observerList){ observer.update(content); } } }
定义具体实现类:
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. * 被观察者具体实现对象:小明 */ public class XiaoMing extends Subject { public void eat() { System.out.println("小明吃饭了。。。开始通知观察者"); super.notifyObservers("小明吃饭了"); } public void run() { System.out.println("小明跑步了。。。开始通知观察者"); super.notifyObservers("小明跑步了"); } }
定义观察者接口:
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. * 观察者接口 */ public interface Observer { /** * 被观察者如果有变化 ,调用该接口通知观察者 * @param content */ void update(String content); }
定义具体实现类:父亲和母亲
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. * 父亲:观察者 */ public class Father implements Observer { public void update(String content) { System.out.println("父亲观察到小明有变化:"+content); } }
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. */ public class Mother implements Observer { public void update(String content) { System.out.println("母亲观察到小明有变化:"+content); } }
测试:
package com.whereta.observer; /** * Vincent 创建于 2016/5/3. * 母亲:观察者 */ public class Main { public static void main(String[] args) { Observer father=new Father(); Observer mother=new Mother(); XiaoMing xiaoMing=new XiaoMing(); xiaoMing.addObserver(father); xiaoMing.addObserver(mother); xiaoMing.eat(); xiaoMing.run(); } }
输出:
小明吃饭了。。。开始通知观察者 父亲观察到小明有变化:小明吃饭了 母亲观察到小明有变化:小明吃饭了 小明跑步了。。。开始通知观察者 父亲观察到小明有变化:小明跑步了 母亲观察到小明有变化:小明跑步了
现在看Subject类,有两点可以优化下:
观察者集合并不是线程安全的
如果在通知一个观察者时耗时很长会卡主整个线程
现在我们来改造下:
package com.whereta.observer; import java.util.List; import java.util.Vector; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * Vincent 创建于 2016/5/3. * 被观察者统一的父类对象 */ public class Subject implements Observable { private final List<Observer> observerList = new Vector<Observer>(); private final Executor executor = Executors.newFixedThreadPool(10); public void addObserver(Observer observer) { observerList.add(observer); } public void removeObserver(Observer observer) { observerList.remove(observer); } public void notifyObservers(String content) { final String temp = content; for (Observer observer : observerList) { final Observer o = observer; executor.execute(new Runnable() { public void run() { try { o.update(temp); } catch (Exception e) { e.printStackTrace(); } } }); } } }
Vector是线程安全的集合
添加线程池,通过多线程通知每个观察者
以上是我们自定义的观察者和被观察者接口,其实在jdk中已经定义了相关接口,现在我们来通过实现jdk中的观察者和被观察者接口完成以上功能
package com.whereta.observer.jdk; import java.util.Observable; /** * Vincent 创建于 2016/5/3. */ public class XiaoMing extends Observable { public void eat() { System.out.println("小明吃饭了。。。开始通知观察者"); super.setChanged(); super.notifyObservers("小明吃饭了"); } public void run() { System.out.println("小明跑步了。。。开始通知观察者"); super.setChanged(); super.notifyObservers("小明跑步了"); } }
package com.whereta.observer.jdk; import java.util.Observable; import java.util.Observer; /** * Vincent 创建于 2016/5/3. * 父亲:观察者 */ public class Father implements Observer { public void update(Observable o, Object arg) { System.out.println("父亲观察到小明有变化:" + arg.toString()); } }
package com.whereta.observer.jdk; import java.util.Observable; import java.util.Observer; /** * Vincent 创建于 2016/5/3. */ public class Mother implements Observer { public void update(Observable o, Object arg) { System.out.println("母亲观察到小明有变化:" + arg.toString()); } }
package com.whereta.observer.jdk; import java.util.Observer; /** * Vincent 创建于 2016/5/3. */ public class Main { public static void main(String[] args) { Observer father=new Father(); Observer mother=new Mother(); XiaoMing xiaoMing=new XiaoMing(); xiaoMing.addObserver(father); xiaoMing.addObserver(mother); xiaoMing.eat(); xiaoMing.run(); } }
小明吃饭了。。。开始通知观察者 母亲观察到小明有变化:小明吃饭了 父亲观察到小明有变化:小明吃饭了 小明跑步了。。。开始通知观察者 母亲观察到小明有变化:小明跑步了 父亲观察到小明有变化:小明跑步了
个人博客:http://www.whereta.com