当一个对象的状态放生改变的时候,如何让依赖于它的所有对象得到通知,并进行相应的处理?
2. UML图Subject:目标对象,通常具有以下功能
-
一个目标对象可以被多个观察者观察
-
目标提供观察者注册和退订的维护
-
当目标状态发生改变时,目标负责通知所有注册的、有效的观察者
Observer:定义观察者接口,提供目标通知时对应的更新方法,这个更新方法进行相应的业务逻辑处理,可以在这个方法回调目标对象,以获取目标对象的数据
ConcreteSubject:具体的目标对象,用来维护目标的状态,当目标状态发生改变时,通知所有注册有效的观察者,让观察者执行相应的处理
ConcreteObserver:观察者的具体对象,用来接收目标的通知,并进行相应的后续处理
3. 具体代码实现代码:4. 研磨设计模式// Subject:public class Subject { //注意:Arraylist里面可以添加null元素 private List<Observer> readers = new ArrayList<>(); public void attach(Observer reader){ if(reader != null){ readers.add(reader); } } public void detach(Observer reader){ if(reader != null){ readers.remove(reader); } } public void notifyAllReaders(){ if(readers.size() != 0){ //通过流的方式来访问 //因为是从Newapaper方法里调用,所有this表示Newspaper实例 readers.forEach(reader -> reader.update(this)); } } }//Newspaper:public class Newspaper extends Subject{ private String content; public String getContent(){ return content; } //维护目标的状态 public void setContent(String content){ //内容更新之后通知所有观察者 this.content = content; notifyAllReaders(); } }// Observer:public interface Observer { public void update(Subject subject); }// Reader:public class Reader implements Observer { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public void update(Subject subject) { System.out.println(name + "收到了报纸\n 报纸的内容为: " + ((Newspaper)subject).getContent() ); } }//Client端public class Client { public static void main(String[] args) { //创建一个报纸,作为被观察者 NewsPaper subject = new NewsPaper(); //创建阅读者,也就是观察者 Reader reader1 = new Reader(); reader1.setName("张三"); Reader reader2 = new Reader(); reader2.setName("李四"); Reader reader3 = new Reader(); reader3.setName("王五"); //注册阅读者 subject.attach(reader1); subject.attach(reader2); subject.attach(reader3); //要出报纸啦 subject.setContent("本期内容是观察者模式"); } }
观察者模式的定义:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式把多个订阅者称为观察者Observer,多个观察者观察的对象的被称为目标Subject。
一个目标可以有任意多个观察者对象,一旦目标的状态发生改变时,所有注册的观察者就会得到通知,然后各个观察者会对通知作出相应的处理,执行相应的业务功能处理,并使自己的状态和目标对象的状态保持一致。
观察者模式的本质:触发联动
Swing中的观察者模式:Swing组件是被观察的目标,而每个实现监听的类就是观察者,监听器的接口就是观察者的接口,在调用addXXXListener方法的时候就相当于注册观察者。当组件被单击时,状态发生改变的时候,就会产生相应的通知,会调用注册的观察者的方法,就是我们所实现的监听器的方法。
扩展:区别对待观察者
Java高级架构∣干货|学习/** * 定义水质监测的目标对象 */public abstract class WaterQualitySubject { /** * 用来保存注册的观察者对象 */ protected List<WatcherObserver> observers = new ArrayList<WatcherObserver>(); /** * 注册观察者对象 * @param observer 观察者对象 */ public void attach(WatcherObserver observer) { observers.add(observer); } /** * 删除观察者对象 * @param observer 观察者对象 */ public void detach(WatcherObserver observer) { observers.remove(observer); } /** * 通知相应的观察者对象 */ public abstract void notifyWatchers(); /** * 获取水质污染的级别 * @return 水质污染的级别 */ public abstract int getPolluteLevel(); }/** * 具体的水质监测对象 */public class WaterQuality extends WaterQualitySubject{ /** * 污染的级别,0表示正常,1表示轻度污染,2表示中度污染,3表示高度污染 */ private int polluteLevel = 0; /** * 获取水质污染的级别 * @return 水质污染的级别 */ public int getPolluteLevel() { return polluteLevel; } /** * 当监测水质情况后,设置水质污染的级别 * @param polluteLevel 水质污染的级别 */ public void setPolluteLevel(int polluteLevel) { this.polluteLevel = polluteLevel; //通知相应的观察者 this.notifyWatchers(); } /** * 通知相应的观察者对象 */ public void notifyWatchers() { //循环所有注册的观察者 for(WatcherObserver watcher : observers){ //开始根据污染级别判断是否需要通知,由这里总控 if(this.polluteLevel >= 0){ //通知监测员做记录 if("监测人员".equals(watcher.getJob())){ watcher.update(this); } } if(this.polluteLevel >= 1){ //通知预警人员 if("预警人员".equals(watcher.getJob())){ watcher.update(this); } } if(this.polluteLevel >= 2){ //通知监测部门领导 if("监测部门领导".equals(watcher.getJob())){ watcher.update(this); } } } } }/** * 水质观察者接口定义 */public interface WatcherObserver { /** * 被通知的方法 * @param subject 传入被观察的目标对象 */ public void update(WaterQualitySubject subject); /** * 设置观察人员的职务 * @param job 观察人员的职务 */ public void setJob(String job); /** * 获取观察人员的职务 * @return 观察人员的职务 */ public String getJob(); }/** * 具体的观察者实现 */public class Watcher implements WatcherObserver{ /** * 职务 */ private String job; public void update(WaterQualitySubject subject) { //这里采用的是拉的方式 System.out.println(job+"获取到通知,当前污染级别为:"+subject.getPolluteLevel()); } public String getJob() { return this.job; } public void setJob(String job) { this.job = job; } }public class Client { public static void main(String[] args) { //创建水质主题对象 WaterQuality subject = new WaterQuality(); //创建几个观察者 WatcherObserver watcher1 = new Watcher(); watcher1.setJob("监测人员"); WatcherObserver watcher2 = new Watcher(); watcher2.setJob("预警人员"); WatcherObserver watcher3 = new Watcher(); watcher3.setJob("监测部门领导"); //注册观察者 subject.attach(watcher1); subject.attach(watcher2); subject.attach(watcher3); //填写水质报告 System.out.println("当水质为正常的时候------------------〉"); subject.setPolluteLevel(0); System.out.println("当水质为轻度污染的时候---------------〉"); subject.setPolluteLevel(1); System.out.println("当水质为中度污染的时候---------------〉"); subject.setPolluteLevel(2); } }