观察者模式
定义了对象之间的一对多的关系,当一个对象状态改变,它的所有依赖的对象都会收到通知并且相应改变。
定义观察者模式的类图:
由主题和一个或多个观察者构成
可以看到,主题(subject)应该具有的方法有:
addObserver() //为主题添加观察者 deleteObserver() //删除观察者 notifyObserver() //通知观察者数据变化
观察者(Observer)应该具有的方法:
update() //接收更新,并作出响应
以最常见的订报服务为例:
1.报社的业务就是出版报纸
2.向某家报社订阅报纸,只要他们有新的报纸出版,就会发送到客户,客户也就会收到新报纸。
3.当客户不想再看报纸的时候,取消订阅,报社就不会送新报纸来。
4.只要报社还在运营,就一定会提供订阅和取消订阅服务。
下面用一个简单的例子模拟:
先列出核心类图:
此实例定义了3个用户(Observer),并为用户提供了订报服务。通过用户注册报社(Subject)的订报服务,报社推送订报和用户取消订报服务来学习观察者模式的使用方法。
核心代码:
Subject接口:
public interface Subject { public void deleteObserver(Observer obj); public void notifyObservers(); void addObserver(Observer obj); }
NewSbuject类:
public class NewsSubject implements Subject { private ArrayList<Observer> objs; private String chinese, english, math; public NewsSubject(){ objs=new ArrayList<Observer>(); } @Override public void addObserver(Observer obj) { // TODO Auto-generated method stub objs.add(obj); } @Override public void deleteObserver(Observer obj) { // TODO Auto-generated method stub objs.remove(obj); } @Override public void notifyObservers() { // TODO Auto-generated method stub System.out.println("报社有新内容更新了,发送更新"); for(Observer temp:objs) temp.update( chinese, english, math); } //动态设置报纸内容 public void setData(String chinese,String english,String math){ this.chinese=chinese; this.english=english; this.math=math; notifyObservers(); } }
Observe接口:
public interface Observer { public void update(String chinese,String english,String math); //这里添加了cancle()方法,用来模拟客户取消订报服务 public void cancle(); }
ChineseObserver类:
public class ChineseObserver implements Observer, Preform { private String content; private Subject sub; public ChineseObserver(NewsSubject sub) { // 为观察者注册 this.sub = sub; sub.addObserver(this); } @Override public void update(String chinese, String english, String math) { // TODO Auto-generated method stub content = chinese; display(); } @Override public void display() { // TODO Auto-generated method stub System.out.println("B订的是语文报,新一期报纸的内容:" + content); } @Override public void cancle() { // TODO Auto-generated method stub sub.deleteObserver(this); System.out.println("B取消订报"); } }
其他的MathObserver,EnglishObserver与之类似。
主程序:
public class Main { static NewsSubject sub; static EnglishObserver eng; static ChineseObserver chi; static MathObserver mat; public static void main(String[] arg) { sub=new NewsSubject(); eng=new EnglishObserver(sub); chi=new ChineseObserver(sub); mat=new MathObserver(sub); sub.setData("今天星期日", "stay hungry ,stay foolish!", "1+2=3"); new Thread(){ public void run() { try { sleep(4000); System.out.println("一天过去了。"); mat.cancle(); sleep(4000); System.out.println("一天过去了。"); sub.setData("今天要上学了!", "keep moving!", "10+10=20"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }; }.start(); } }
运行可以看到结果:
报社有新内容更新了,发送更新 A订的是英语报,新一期报纸的内容:stay hungry ,stay foolish! B订的是语文报,新一期报纸的内容:今天星期日 C订的是数学报报,新一期报纸的内容:1+2=3 一天过去了。 C取消订报 一天过去了。 报社有新内容更新了,发送更新 A订的是英语报,新一期报纸的内容:keep moving! B订的是语文报,新一期报纸的内容:今天要上学了!
通过这样就可以看到观察者模式的使用方法和运行形式,另外这个例子中只是实现报社主动推送报纸服务,可另外扩展为用户主动请求更新,这里不做实现,读者另行实现。同时Java有内置的观察者模式,通过java.util包内的Observer接口和Observable类来实现。不过只要你掌握的观察者模式,哪一种方法来实现也是易如反掌的。