标签:
观察者模式是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。这一模式中的关键对象是目标(Subject)和观察者(Obserber)。一个目标可以有任意个观察者,一旦目标状态发生改变,所有的观察者将得到通知。这种交互也称为发布-订阅。
观察者模式的适用场景:
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。
基本结构:
Subject<---------ConcreteSubject
Observer<----------ConcreteObserver
Subject(目标):目标知道它的观察者,可以有任意个观察者;提供attach()、detach()、notifyObservers()方法接口。
ConcreteSubject(具体目标):写入具体目标对象的状态或内容(getter and setter方法),并且在它们的状态发生改变时会向它的观察者发出通知。
Observer(观察者):定义目标发生改变时需获得通知的对象定义一个接口,Update()方法。
ConcreteObserver(具体观察者):维护一个指向ConcreteSubject对象的引用;存储观察者自身的状态,实现Observer接口使自身状态与目标状态保持一致。
观察者模式允许独立的改变目标和观察者。可以单独复用目标对象而无需同时复用其观察者,反之亦然。
观察者模式的优点:目标与观察者之间的抽象耦合,耦合与抽象达到最小;支持广播更新。
观察者模式的缺点:容易引起误广播,即其中一个观察者修改了目标的状态,则其他观察者也收到了该更新。
观察者模式的实现需要考虑以下几个关键点:1.创建目标到其观察者之间的映射;2.观察多个目标;3.谁触发更新;4.对已删除目标的悬挂引用;5.在发出通知之前一定要确保目标的状态自身是一致的;6.避免特定于观察者的更新协议——推/拉模型:推模型是指目标向观察者发送关于改变的详细信息,而不管他们需要与否。拉模型是指目标除最小通知外什么也不送出,而此后由观察者显示地向目标询问细节。7.显示地指定感兴趣的改变。即可以让观察者对感兴趣的目标才接受通知。
下面通过一段代码来演示一下观察者模式的应用案例:
Subject.java
package com.observer.classic; import java.util.ArrayList; import java.util.List; /** * 观察者模式 * 目标对象 * @author zzw */ public class Subject { //不同兴趣点观察者线性列表 private List<Observer> observersAll = new ArrayList<Observer>(); private List<Observer> observersMusic = new ArrayList<Observer>(); private List<Observer> observersSport = new ArrayList<Observer>(); private List<Observer> observersMovie = new ArrayList<Observer>(); //增加观察者 public void attach(Observer observer) { String interest = observer.getObserverInterest(); if("All".equals(interest)) { observersAll.add(observer); } else if("Music".equals(interest)) { observersMusic.add(observer); } else if("Sport".equals(interest)) { observersSport.add(observer); } else if("Movie".equals(interest)) { observersMovie.add(observer); } } //删除观察者 public void detach(Observer observer) { String interest = observer.getObserverInterest(); if("All".equals(interest)) { observersAll.remove(observer); } else if("Music".equals(interest)) { observersMusic.remove(observer); } else if("Sport".equals(interest)) { observersSport.remove(observer); } else if("Movie".equals(interest)) { observersMovie.remove(observer); } } public void notifyObservers(String subjectTag) { if("Music".equals(subjectTag)) { for(Observer observer : observersMusic) { observer.update(this); } } else if("Sport".equals(subjectTag)) { for(Observer observer : observersSport) { observer.update(this); } } else if("Movie".equals(subjectTag)) { for(Observer observer : observersMovie) { observer.update(this); } } for(Observer observer : observersAll) { observer.update(this); } } }
Observer.java
package com.observer.classic; /** * 观察者接口 * @author zzw * */ public interface Observer { public void update(Subject subject); public String getObserverInterest(); }
ConcreteSubject.java
package com.observer.classic; /** * 具体的目标对象 * 负责把目标的状态信息存入到相应的观察者身上 * @author zzw */ public class ConcreteSubject extends Subject { //相应目标的状态(内容) private String subjectState; //目标通知的分类标签 private String subjectTag; public String getSubjectTag() { return subjectTag; } public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState,String subjectTag) { this.subjectState = subjectState; this.subjectTag = subjectTag; this.notifyObservers(subjectTag); } }
ConcreteObserver.java
package com.observer.classic; public class ConcreteObserver implements Observer { //观察者姓名 private String observerName; //观察者兴趣点 private String observerInterest; //观察者状态信息 private String observerState; public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } public String getObserverState() { return this.observerState; } public String getObserverInterest() { return observerInterest; } public void setObserverInterest(String observerInterest) { this.observerInterest = observerInterest; } @Override public void update(Subject subject) { //获取目标状态,以保持更新 observerState = ((ConcreteSubject) subject).getSubjectState(); System.out.println(observerName + "收到了一条通知:" + observerState); } }
Test.java
package com.observer.classic; public class Test { public static void main(String[] args) { // 创建推送内容1 ConcreteSubject concreteSubject = new ConcreteSubject(); // 创建观察者(即待通知对象) ConcreteObserver concreteObserver1 = new ConcreteObserver(); concreteObserver1.setObserverName("张三"); concreteObserver1.setObserverInterest("All"); ConcreteObserver concreteObserver2 = new ConcreteObserver(); concreteObserver2.setObserverName("李四"); concreteObserver2.setObserverInterest("Music"); ConcreteObserver concreteObserver3 = new ConcreteObserver(); concreteObserver3.setObserverName("王二麻子"); concreteObserver3.setObserverInterest("Sport"); ConcreteObserver concreteObserver4 = new ConcreteObserver(); concreteObserver4.setObserverName("刘老五"); concreteObserver4.setObserverInterest("Movie"); //注册观察者 concreteSubject.attach(concreteObserver1); concreteSubject.attach(concreteObserver2); concreteSubject.attach(concreteObserver3); concreteSubject.attach(concreteObserver4); //发布通知1 System.out.println("消息一:"); concreteSubject.setSubjectState("周杰伦发了一张新专辑《哎哟,不错哦》","Music"); //发布通知2 System.out.println("消息二:"); concreteSubject.setSubjectState("姚明宣布退役了","Sport"); //发布通知3 System.out.println("消息三:"); concreteSubject.setSubjectState("新电影《栀子花开》上映了","Movie"); } }
运行结果
消息一:
李四收到了一条通知:周杰伦发了一张新专辑《哎哟,不错哦》
张三收到了一条通知:周杰伦发了一张新专辑《哎哟,不错哦》
消息二:
王二麻子收到了一条通知:姚明宣布退役了
张三收到了一条通知:姚明宣布退役了
消息三:
刘老五收到了一条通知:新电影《栀子花开》上映了
张三收到了一条通知:新电影《栀子花开》上映了
下面使用另外一种方法来实现有区分的观察者,即把notifyObservers方法交由子类去实现,而父类仅仅提供抽象方法。
WeatherSubject.java
package com.observer.advanced; /** * 观察者模式的高级 * 允许推送内容到特定的观察者 * notifyObservers()在子类中实现 */ import java.util.ArrayList; import java.util.List; public abstract class WeatherSubject { List<Observer> observers = new ArrayList<Observer>(); public void attach(Observer observer) { observers.add(observer); } public void detach(Observer observer) { observers.remove(observer); } //留到子类中去实现 protected abstract void notifyObservers(); }
ConcreteWeatherSubject.java
package com.observer.advanced; public class ConcreteWeatherSubject extends WeatherSubject { //目标状态 private String subjectState; public ConcreteWeatherSubject(String subjectState) { super(); this.subjectState = subjectState; } public String getSubjectState() { return subjectState; } public void setSubjectState(String subjectState) { this.subjectState = subjectState; //一旦目标得到修改,所有的观察者都会收到通知 this.notifyObservers(); } @Override protected void notifyObservers() { /** * 由于张三只接受下雪的天气预报,李四只接受下雨的天气预报,其他观察者无限制 */ for(Observer observer : observers) { if("下雪".equals(subjectState)) { if("张三".equals(observer.getObserverName())) observer.update(this); else if(!"李四".equals(observer.getObserverName())) observer.update(this); } else if("下雨".equals(subjectState)) { if("李四".equals(observer.getObserverName())) observer.update(this); else if(!"张三".equals(observer.getObserverName())) observer.update(this); } else if(!"李四".equals(observer.getObserverName())&&!"张三".equals(observer.getObserverName())) observer.update(this); } } }
Observer.java
package com.observer.advanced; public interface Observer { public void update(WeatherSubject subject); //设置观察者名称 public String getObserverName(); public void setObserverName(String observerName); public String getObserverSex(); public void setObserverSex(String observerSex); public String getObserverAge(); public void setObserverAge(String observerAge); }
ConcreteObserver.java
package com.observer.advanced; public class ConcreteObserver implements Observer { private String observerName; private String observerSex; private String observerAge; public ConcreteObserver(String observerName, String observerSex, String observerAge) { super(); this.observerName = observerName; this.observerSex = observerSex; this.observerAge = observerAge; } @Override public void update(WeatherSubject subject) { // 推送内容 String content = ((ConcreteWeatherSubject)subject).getSubjectState(); System.out.println(this.getObserverName()+"("+this.getObserverSex()+","+this.getObserverAge()+")收到了一条消息:"+content); } @Override public String getObserverName() { return observerName; } @Override public void setObserverName(String observerName) { this.observerName = observerName; } public String getObserverAge() { return observerAge; } public void setObserverAge(String observerAge) { this.observerAge = observerAge; } public String getObserverSex() { return observerSex; } public void setObserverSex(String observerSex) { this.observerSex = observerSex; } }
Test.java
package com.observer.advanced; public class Test { public static void main(String[] args) { //新建三个观察者 Observer concreteObserver1 = new ConcreteObserver("张三", "男", "22岁"); Observer concreteObserver2 = new ConcreteObserver("李四", "男", "30岁"); Observer concreteObserver3 = new ConcreteObserver("玛丽", "女", "25岁"); //新建目标内容:下雪 WeatherSubject concreteWeatherSubject1 = new ConcreteWeatherSubject("下雪"); concreteWeatherSubject1.attach(concreteObserver1); concreteWeatherSubject1.attach(concreteObserver2); concreteWeatherSubject1.attach(concreteObserver3); concreteWeatherSubject1.notifyObservers(); //新建目标内容:下雨 WeatherSubject concreteWeatherSubject2 = new ConcreteWeatherSubject("下雨"); concreteWeatherSubject2.attach(concreteObserver1); concreteWeatherSubject2.attach(concreteObserver2); concreteWeatherSubject2.attach(concreteObserver3); concreteWeatherSubject2.notifyObservers(); //新建目标内容:晴天 WeatherSubject concreteWeatherSubject3 = new ConcreteWeatherSubject("晴天"); concreteWeatherSubject3.attach(concreteObserver1); concreteWeatherSubject3.attach(concreteObserver2); concreteWeatherSubject3.attach(concreteObserver3); concreteWeatherSubject3.notifyObservers(); } }
运行结果:
张三(男,22岁)收到了一条消息:下雪
玛丽(女,25岁)收到了一条消息:下雪
李四(男,30岁)收到了一条消息:下雨
玛丽(女,25岁)收到了一条消息:下雨
玛丽(女,25岁)收到了一条消息:晴天
标签:
原文地址:http://my.oschina.net/zzw922cn/blog/483089