观察者模式
观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
观察者模式一般有以下几种角色:
● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法snedNotify()。目标类可以是接口,也可以是抽象类或具体类。
● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
具体代码演示:
工程结构如下:
创建发布消息的实体类:
1 package com.sunyard.bean; 2 3 /** 4 * <p>发布招聘信息类</p> 5 * @author:774346810@qq.com 6 * @date:2017-6-25 7 */ 8 public class Job { 9 private String title;//招聘标题 10 11 public Job(String title) { 12 this.title = title; 13 } 14 15 public String getTitle() { 16 return title; 17 } 18 19 public void setTitle(String title) { 20 this.title = title; 21 } 22 }
创建抽象观察者:
1 package com.sunyard.observer; 2 3 import com.sunyard.subject.Subject; 4 5 /** 6 * <p>抽象观察者类</p> 7 * @author:774346810@qq.com 8 * @date:2017-6-25 9 */ 10 public interface Observer { 11 //声明响应方法,当某个状态触发时,调用该方法进行相应的操作 12 public void update(Subject subject); 13 }
具体观察者:
1 package com.sunyard.observer; 2 3 import com.sunyard.subject.HR; 4 import com.sunyard.subject.HeadHunter; 5 import com.sunyard.subject.Subject; 6 7 /** 8 * <p>具体观察者</p> 9 * @author:774346810@qq.com 10 * @date:2017-6-25 11 */ 12 public class JobSeeker implements Observer{ 13 private String name; 14 15 public JobSeeker(String name){ 16 this.name = name; 17 } 18 19 @Override 20 public void update(Subject subject) { 21 if(subject instanceof HeadHunter){ 22 System.out.println("求职者的名字是:" + name); 23 System.out.println("HeadHunter更新了职位信息"); 24 System.out.println(((HeadHunter) subject).getName()); 25 System.out.println("职位信息如下:"); 26 System.out.println(((HeadHunter) subject).getLastJob().getTitle()); 27 } else if(subject instanceof HR){ 28 System.out.println("求职者的名字是:" + name); 29 System.out.println("HeadHunter更新了职位信息"); 30 System.out.println(((HR) subject).getName()); 31 System.out.println("职位信息如下:"); 32 System.out.println(((HR) subject).getLastJob().getTitle()); 33 } 34 } 35 36 }
1 package com.sunyard.observer; 2 3 import com.sunyard.subject.HR; 4 import com.sunyard.subject.HeadHunter; 5 import com.sunyard.subject.Subject; 6 7 /** 8 * <p>具体观察者</p> 9 * @author:774346810@qq.com 10 * @date:2017-6-25 11 */ 12 public class DBManager implements Observer{ 13 private String name; 14 15 public DBManager(String name) { 16 this.name = name; 17 } 18 19 @Override 20 public void update(Subject subject) { 21 if(subject instanceof HeadHunter){ 22 System.out.println("求职者的名字是:" + name); 23 System.out.println("HeadHunter更新了职位信息"); 24 System.out.println(((HeadHunter) subject).getName()); 25 System.out.println("职位信息如下:"); 26 System.out.println(((HeadHunter) subject).getLastJob().getTitle()); 27 } else if(subject instanceof HR){ 28 System.out.println("求职者的名字是:" + name); 29 System.out.println("HeadHunter更新了职位信息"); 30 System.out.println(((HR) subject).getName()); 31 System.out.println("职位信息如下:"); 32 System.out.println(((HR) subject).getLastJob().getTitle()); 33 } 34 } 35 }
创建抽奖被观察者:
1 package com.sunyard.subject; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import com.sunyard.observer.Observer; 7 8 /** 9 * <p>抽象被观察者</p> 10 * @author:774346810@qq.com 11 * @date:2017-6-25 12 */ 13 public abstract class Subject { 14 //定义一个观察者集合用于存储所有的观察者对象 15 protected List<Observer> observers = new ArrayList<Observer>(); 16 17 //注册方法,用于向观察者集合中增加一个观察者 18 public void attach(Observer observer){ 19 observers.add(observer); 20 } 21 22 //注销方法,用于在观察者集合中删除一个观察者 23 public void detach(Observer observer) { 24 observers.remove(observer); 25 } 26 27 //声明抽象通知方法 28 public abstract void sendNotify(Subject subject); 29 }
创建具体被观察者:
1 package com.sunyard.subject; 2 3 import com.sunyard.bean.Job; 4 import com.sunyard.observer.Observer; 5 /** 6 * <p>具体被观察者</p> 7 * @author:774346810@qq.com 8 * @date:2017-6-25 9 */ 10 public class HeadHunter extends Subject{ 11 private String name; 12 13 private Job myJobLast;//最新发布的招聘信息 14 15 public HeadHunter(String name){ 16 this.name = name; 17 } 18 19 // 发布招聘,发布时发送通知 20 public void publishJob(Job job) { 21 myJobLast = job; 22 sendNotify(this); 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public Job getLastJob() { 30 return myJobLast; 31 } 32 33 @Override 34 public void sendNotify(Subject subject) { 35 //遍历观察者集合,调用每一个观察者的响应方法 36 for(Observer observer : observers){ 37 observer.update(subject); 38 } 39 } 40 41 }
1 package com.sunyard.subject; 2 3 import com.sunyard.bean.Job; 4 import com.sunyard.observer.Observer; 5 6 /** 7 * <p>具体被观察者</p> 8 * @author:774346810@qq.com 9 * @date:2017-6-25 10 */ 11 public class HR extends Subject{ 12 private String name; 13 14 private Job myJobLast;//最新发布的招聘 15 16 public HR(String name){ 17 this.name = name; 18 } 19 20 // 发布招聘,发布时发送通知 21 public void publishJob(Job job) { 22 myJobLast = job; 23 sendNotify(this); 24 } 25 26 public Job getLastJob() { 27 return myJobLast; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 @Override 35 public void sendNotify(Subject subject) { 36 //遍历观察者集合,调用每一个观察者的响应方法 37 for (Observer observer : observers) { 38 observer.update(subject); 39 } 40 } 41 42 }
观察者测试类:
1 package com.sunyard.test; 2 3 import com.sunyard.bean.Job; 4 import com.sunyard.observer.DBManager; 5 import com.sunyard.observer.JobSeeker; 6 import com.sunyard.subject.HR; 7 import com.sunyard.subject.HeadHunter; 8 9 /** 10 * <p>测试观察者</p> 11 * @author:774346810@qq.com 12 * @date:2017-6-25 13 */ 14 public class ObserverPattern { 15 public static void main(String[] args) { 16 HeadHunter headHunter = new HeadHunter("猎头"); 17 18 HR hr = new HR("人事"); 19 20 JobSeeker jobSeeker1 = new JobSeeker("求职者1"); 21 JobSeeker jobSeeker2 = new JobSeeker("求职者2"); 22 JobSeeker jobSeeker3 = new JobSeeker("求职者3"); 23 24 DBManager dbManager = new DBManager("管理员"); 25 26 //完成订阅注册添加 27 headHunter.attach(jobSeeker1); 28 headHunter.attach(jobSeeker2); 29 headHunter.attach(jobSeeker3); 30 headHunter.attach(dbManager); 31 32 //猎头发布招聘,将会依次给观察者发通知 33 headHunter.publishJob(new Job("工作信息1")); 34 35 //移除某个观察者 36 headHunter.detach(jobSeeker2); 37 38 //再次发布招聘,测试移除订阅 39 headHunter.publishJob(new Job("工作信息2")); 40 41 hr.attach(jobSeeker2); 42 hr.attach(dbManager); 43 44 hr.publishJob(new Job("工作信息3")); 45 } 46 }
输入结果:
1 求职者的名字是:求职者1 2 HeadHunter更新了职位信息 3 猎头 4 职位信息如下: 5 工作信息1 6 求职者的名字是:求职者2 7 HeadHunter更新了职位信息 8 猎头 9 职位信息如下: 10 工作信息1 11 求职者的名字是:求职者3 12 HeadHunter更新了职位信息 13 猎头 14 职位信息如下: 15 工作信息1 16 求职者的名字是:管理员 17 HeadHunter更新了职位信息 18 猎头 19 职位信息如下: 20 工作信息1 21 求职者的名字是:求职者1 22 HeadHunter更新了职位信息 23 猎头 24 职位信息如下: 25 工作信息2 26 求职者的名字是:求职者3 27 HeadHunter更新了职位信息 28 猎头 29 职位信息如下: 30 工作信息2 31 求职者的名字是:管理员 32 HeadHunter更新了职位信息 33 猎头 34 职位信息如下: 35 工作信息2 36 求职者的名字是:求职者2 37 HeadHunter更新了职位信息 38 人事 39 职位信息如下: 40 工作信息3 41 求职者的名字是:管理员 42 HeadHunter更新了职位信息 43 人事 44 职位信息如下: 45 工作信息3