资源描述
单击此处编辑母版标题样式,.,Observer,模式,1,.,从生活中走进观察者模式,在日常生活中,常常会有这样的情形:当某件事情发生时,就应该通知所有的相关者。例如,如果我们的课程改变了时间和地点,就应该通知所有选了这门课程的同学。,在软件设计中,也有类似的问题:当一个对象的状态发生变化时,如何能够通知与其相关的所有其他对象,而不用修改该对象的代码?,2,.,初析观察者模型,在许多设计中,经常涉及到多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化。,例如:求职中心与求职者,3,.,观察者模型的定义,1,、定义对象间的一种,一对多,的依赖关系,当一个对象的,状态发生变化,时,,所有依赖于它的对象都得到通知并被自动更新。,2,、别名:,依赖(,Dependents,);发布,-,订阅(,Publish-Subscribe,)。,Observer,Pattern(Another,Name:Dependents,Publish-Subscribe),Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.,4,.,对概念的加深理解,观察者模式中有一个“,主题,”对象和若干“,观察者,”对象,主题和观察者之间是一对多的依赖关系。,当主题的状态发生变化时,所有观察者都得到通知。,例如:求职中心为主题,求职者为观察者,5,.,观察者模型设计的动机,1,、将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象的一致性。我们不希望为了维持一致性使各类紧密耦合,因为这样降低了它们的可重用性。,2,、观察者模式使得任意数目的观察者不必知道彼此的存在,且主题发生变化时可以得到主题的通知,而同步改变状态。是一种很轻松的耦合。具有很好的可重用性。,6,.,设计模型的原则,1,、将不变部分与固定比便的部分相离。,对该原则的理解是:将变化的部分拿来进行封装,以便以后你可以修改它而不会影响那些不变的部分。,这一原则几乎是所有设计模式的基础,所有设计模式都提供一种机制:让系统的某些部分独立于其他部分而发生变化。,7,.,2,、对接口编程,而不是对实现编程,实现观察者模式的过程:实现观察者模式有很多形式,比较直观的一种是“订阅,-,通知,-,撤销订阅”的形式下。,下面我们来详细的描述这一过程:,观察者,观察者(,observer,)将自己注册到被观察对象(,subject),中,被观察对象(目标)将观察者存放在一个容器(,container,)里。,8,.,3、被观察对象,被观察对象发生了某些变化(如,发行方发行新的报纸,),从容器中得到所有注册过的观察者,将变化通知观察者,4、撤销观察,观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。(观察者将将自己注册到观察者容器时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息通知所有的观察者。基于接口,而不是具体的实现,这一点位程序提供了更大的灵活性。,9,.,观察者模式的结构中的角色,主题(,Subject,),观察者(,Observer,),具体主题(,ConcreteSubject,),具体观察者(,ConcreteObserver,),10,.,观察者模式里角色的详细解析,1,、,抽象主题(,Subject,)角色,:主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者,(Observable),角色;,抽象主题角色,有时又叫做抽象被观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。,11,.,2,、抽象观察者(,Observer,)角色,:为所有的具体观察者定义一个接口,在得到通知时更新自己;,抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。,12,.,3,、具体主题(,ConcreteSubject,)角色,:保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;,具体主题角色,通常用一个具体子类实现。,13,.,4,、具体观察者(,ConcreteObserver,)角色,:保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。,具体观察者角色,通常用一个具体子类实现。,14,.,呵呵,观察者模式类图,15,.,举例说明模式的结构的描述与使用,例:有一个大学毕业生和一个归国留学者都希望能及时知道求职中心最新的职业需求信息。,1,主题,:,Subject.java,public interface Subject /,定义接口,public void,addObserver(Observer,o);/,接口方法,1,public void,deleteObserver(Observer,o);/,接口方法,2,public void,notifyObservers,();/,接口方法,3,16,.,2,观察者,:,Obsever.java,public interface Observer /,定义接口观察者,public void,hearTelephone(String,heardMess,);/,接口方法,hearTelephone,(),用来更新数据,17,.,3,具体主题,SeekJobCenter.java,import,java.util.ArrayList,;,public class,SeekJobCenter,implements Subject,/,实现接口,String mess;,boolean,changed;/,定义,bool,型变量,ArrayList,personList,;/,定义数组列表,SeekJobCenter,()/,方法,找工作中心,personList,=new,ArrayList,();/,实例一个数组列表,mess=“”;/,信息初始值为空,changed=false;,18,.,public void,addObserver,(Observer,o),if(!,(,personList.contains(o,),),)/,若列表中不包含对象,,personList.add(o,);/,则向列表增加该对象,public void,deleteObserver,(Observer,o),if(personList.contains(o,)/,若列表中包含该对象,,personList.remove(o,);/,则从列表移出该对象,19,.,public void,notifyObservers,()/,方法,信息公示,if(changed,)/,若信息改变,for(int,i=0;i,personList.size();i,+)/,则遍历数组列表,Observer,observer,=,personList.get(i,);,observer.hearTelephone(mess,);/,更新列表,changed=false;,public void,giveNewMess(String,str,)/,方法,if(str.equals(mess,)/,检测两个对象(信息)是否相同,changed=false;/,若相同,则将,changed,置为,false,,即信息,else mess=,str,;/,未改变,;,反之,则将,changed,置为,true,,,changed=true;/,即信息改变,20,.,4,具体观察者,_1,UniversityStudent.java,import,java.io,.*;,public class,UniverStudent,implements Observer /,实现接口,本科生类,Subject,subject,;,File,myFile,;,UniverStudent(Subject,subject,String,fileName,),this.subject,=subject;,subject.addObserver(this,);/,使当前实例成为,subject,所引用的具体主题的观察者,myFile,=new,File(fileName,);/,读取文件名,public void,hearTelephone(String,heardMess,)/,实现方法,try,RandomAccessFile,out=new,RandomAccessFile(myFile,rw,);,out.seek(out.length,();,byte b=,heardMess.getBytes,();,out.write(b,);/,更新文件中的内容,System.out.print,(,我是一个大学生,);,System.out.println,(,我向文件,+,myFile.getName,()+,写入如下内容,:);,System.out.println(heardMess,);,catch(IOException,exp),System.out.println(exp.toString,();,21,.,5,应用,Application.java,public class Application,public static void,main(String,args,)/,主函数,SeekJobCenter,center=new,SeekJobCenter,();/,实例一个对象,找工作中心,UniverStudent,zhangLin,=,new,UniverStudent(center,“A.txt,”);/,实例一个对象,本科生,HaiGui,wangHao,=new,HaiGui(center,“B.txt,”);/,实例一个对象,海归,center.giveNewMess,(“,腾辉公司需要,10,个,java,程序员。,”);/,添加新信息,center.notifyObservers,();/,公示信息,center.giveNewMess,(,海景公司需要,8,个动画设计师。,);,center.notifyObservers,();,center.giveNewMess,(,仁海公司需要,9,个电工。,);,center.notifyObservers,();,center.giveNewMess,(,仁海公司需要,9,个电工。,);,center.notifyObservers,();,22,.,运行结果,23,.,观察者模式的优点,1,、,具体主题和具体观察者是松耦合关系,。由于主题(,Subject,)接口仅仅依赖于观察者(,Observer,)接口,因此具体主题只是知道它的观察者是实现观察者(,Observer,)接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题(,Subject,)接口,因此具体观察者只是知道它依赖的主题是实现主题(,subject,)接口的某个类的实例,但不需要知道具体是哪个类。,24,.,2,、观察模式满足“开,-,闭原则”,。主题(,Subject,)接口仅仅依赖于观察者(,Observer,)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(,Observer,)接口,因此如果增加新的实现观察者(,Observer,)接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题(,Observer,)接口,如果增加新的实现主题(,Subject,)接口的类,也不必修改创建具体观察者类的代码。,25,.,观察者模式的,缺点,1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。2、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。3、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。4、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。,26,.,观察者模式与其他模式的关系,1,、,观察者模式与备忘录模式的关系,观察者模式使用了备忘录模式(,Memento Pattern,),暂时将观察者对象存储在被观察者对象里面,观察者模式与,MVC,模式的关系,观察者模式可以用来实现,MVC,模式。观察者模式中的主题便是,MVC,模式中的模型加控制器,而观察者便是视图,一般情况下,,MVC,是观察者模式、组合模式、策略模式等设计模式的组合。,27,.,回顾观察者模型,下面我们来讨论一个生活中实际问题,场景:,我和妹妹跟妈妈说:“妈妈,我和妹妹在院子里玩;饭做好了叫我们一声。”请问这是什么模式?能否给出类图说明?,28,.,问题的解析:,这是观察者模式。我和妹妹让妈妈告诉我们饭做好了,这样我们就可以来吃饭了。换用较为技术化的语言来说,当系统的主题(饭)发生变化时,就告诉系统的其它部份(观察者们,也就是妈妈、我和妹妹),使其可以调整内部状态(有开始吃饭的准备),并采取相应的行动(吃饭)。,29,.,图,11,、系统的类图。,系统的类图说明如下。,30,.,以上是我们对观察模型的理解,谢谢!,31,.,
展开阅读全文