观察者模式
观察者模式:定义对象之间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知并自动更新。
概述
观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。模式中有一个“主题”和若干个“观察者”。当主题状态发生变化时,观察者得到通知。
模式的结构
模式的使用
下面通过一个简单的问题描述。该问题是:有一个大学生和一个海归留学者都希望能够及时知道求职中心的最新职业需求信息。
主题
主题接口规定了具体主题需要实现的添加、删除观察者已经通知观察者更新数据的方法。
/** * 主题 */ public interface Subject { public void addObserver(Observer o); public void deleteObserver(Observer o); public void notifyObservers(); }
观察者
是一个接口,规定了具体观察者用来更新数据的方法。
/** * 观察者 */ public interface Observer { public void hearTelephone(String heardMess); }
具体主题
具体主题中使用一个List来存放观察者,mess表示职业需求信息,当职业需求信息发生改变时,通知List里面的所有观察者。
import java.util.ArrayList; /** * 具体主题 */ public class SeekJobCenter implements Subject{ String mess; boolean changed; ArrayList<Observer> personList; SeekJobCenter(){ personList=new ArrayList<Observer>(); mess=""; changed=false; } public void addObserver(Observer o){ if(!(personList.contains(o))){ personList.add(o); } } public void deleteObserver(Observer o){ if(personList.contains(o)){ personList.remove(o); } } public void notifyObservers(){ if(changed){ for(Observer observer:personList){ observer.hearTelephone(mess); } changed=false; } } public void giveNewMess(String str){ if(str.equals(mess)){ changed=false; }else{ mess=str; changed=true; } } }
具体观察者
这里,我们实现接口Observer的类有两个:一个是UniversityStudent类,一个是HaiGui类。
UniversityStudent类如下:
/** * 具体观察者:大学生 */ public class UniversityStudengt implements Observer{ Subject subject; String name; UniversityStudengt(Subject subject,String name){ this.subject=subject; subject.addObserver(this); this.name=name; } public void hearTelephone(String heardMess){ System.out.println("我是大学生,名字为"+name+"我收到职业需求新信息:"+heardMess); } }
HaiGui类如下:
/** * 具体观察者:海归 */ public class HaiGui implements Observer { Subject subject; String name; HaiGui(Subject subject,String name){ this.subject=subject; subject.addObserver(this); this.name=name; } public void hearTelephone(String heardMess){ System.out.println("我是海归,名字为"+name+"我收到职业需求新信息:"+heardMess); } }
应用程序
/** * 应用程序 */ public class Application { public static void main(String[] args){ SeekJobCenter center = new SeekJobCenter(); Observer person1 = new UniversityStudengt( center,"Tom"); Observer person2 = new HaiGui(center,"Jerry"); center.giveNewMess("招聘信息001"); center.notifyObservers(); center.giveNewMess("招聘信息002"); center.notifyObservers(); //重复信息,不会通知 center.giveNewMess("招聘信息002"); center.notifyObservers(); //删除一个观察者 center.deleteObserver(person1); center.giveNewMess("招聘信息003"); center.notifyObservers(); } }
我是大学生,名字为Tom我收到职业需求新信息:招聘信息001
我是海归,名字为Jerry我收到职业需求新信息:招聘信息001
我是大学生,名字为Tom我收到职业需求新信息:招聘信息002
我是海归,名字为Jerry我收到职业需求新信息:招聘信息002
我是海归,名字为Jerry我收到职业需求新信息:招聘信息00
"推数据"与拉数据
推数据:具体主题将变化后的数据全部交给观察者
拉数据:具体观察者收到通知后,调用具体主题提供的方法得到数据
观察者模式的优点
- 具体主题和具体观察者是松耦合关系。主题接口仅仅依赖观察者接口,具体主题并不需要知道具体观察者是哪个类,反之亦然。
- 观察者满足“开-闭原则”。
观察者模式的应用场景
- 当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合。
- 当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少个对象需要更新数据。
Java API相关类和接口
java.util.Observable相当于观察者模式的主题接口,但它其实是一个类,有以下方法:
- addObserver(Observer o)
- clearChanged()
- countObservers()
- deleteObserver(Observer o)
- deleteObservers()
- hasChanged()
- notifyObservers()
- notifyObservers(Object arg)
- setChanged()
java.util.Observer相当于观察者接口,它是一个接口。有一个update()方法
联系方式:wuchaodzxx@126.com