1.1概述
在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化,在这样的情况下就可以使用观察者模式。
例如,某些寻找工作的人对“求职中心”的职业需求信息的变化非常关心,很想追踪“求职中心”中职业需求信息的变化。一位想知道“求职中心”职业需求信息变化的人需要成为“求职中心”的求职者,即让求职中心把自己登记到求职中心的“求职者”列表中,当一个人成为求职中心的求职者后,求职中心就会及时通知他最新的职业需求信息。
观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。前面所述的“求职中心”相当于观察者模式的一个具体“主题”;每个“求职者”相当于观察者模式中的一个具体“观察者”。
1.2模式的结构
观察者模式的结构中包含四种角色:
(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。
(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。
(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
观察者模式结构的类图如下所示:
1.3观察者模式的优点
(1)具体主题和具体观察者是松耦合关系。由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。
(2)观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。
1.4适合使用观察者模式的情景
(1)当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合。
(2)当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少对象需要更新数据。
1.5观察者模式的应用
下面通过一个简单的问题来描述观察者模式中所涉及的各个角色,这个简单的问题是:有一个大学毕业生和一个归国留学者都希望能及时知道“求职中心”最炫的职业需求信息。
首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图3所示:
图3 具体编写类及接口与类图对应关系
(1)主题(Subject)
本问题中,主题接口Subject规定了具体主题需要实现的添加、删除观察者以及通知观察者更新数据的方法。其代码如下:
package com.liuzhen.two_observer; public interface Subject { public void addObserver(Observer o); public void deleteObserver(Observer o); public void notifyObservers(); }
(2)观察者(Observer)
观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。对于本问题,观察者规定的方法是:hearTelephone()(相当于观察者模式类图中的update()方法),即要求具体观察者都通过实现hearTelephone()方法(模拟接听电话)来更新数据。其代码如下:
package com.liuzhen.two_observer; public interface Observer { public void hearTelephone(String heardMess); }
(3)具体主题(ConcreteSubject)
具体主题维护着一个String字符串,用来表示“求职中心”的职业需求信息,当该String字符串发生变化时,具体主题遍历存放观察者引用集合。具体代码如下:
package com.liuzhen.two_observer; 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(int i = 0;i < personList.size();i++){ Observer observer = personList.get(i); observer.hearTelephone(mess); //让所有的观察者接听电话 } } } public void getNewMess(String str){ //判断信息是否是新发布的 if(str.equals(mess)){ changed = false; } else{ mess = str; changed = true; } } }
(4)具体观察者(ConcreteObserver)
本问题中,实现观察者接口Observer的类有两个:一个UniversityStudent类,另一个是HaiGui。UniversityStudent类的实例调用hearTelephone(String heardMess)方法时,会将参数引用的字符串保存到一个文件中。HaiGui类的实例调用hearTelephone(String heardMess)方法时,如果参数引用的字符串中包含有“程序员”或软件,就将信息保存到一个文件中。
UniversityStudent类代码如下:
package com.liuzhen.two_observer; import java.io.*; public class UniversityStudent implements Observer { Subject subject; File myFile; UniversityStudent(Subject subject,String fileName){ this.subject = subject; subject.addObserver(this); //使当前实例成为subject所使用的具体主题的观察者 myFile = new File(fileName); } public void hearTelephone(String heardMess) { try{ RandomAccessFile out1 = new RandomAccessFile(myFile,"rw"); out1.seek(out1.length()); byte[] b = heardMess.getBytes(); out1.write(b); //更新文件中的内容 System.out.print("我是一个大学生,"); System.out.println("我向文件"+myFile.getName()+"写入如下内容:"); System.out.println(heardMess); } catch(IOException exp){ System.out.println(exp.toString()); } } }
HaiGui类代码如下:
package com.liuzhen.two_observer; import java.io.*; public class HaiGui implements Observer { Subject subject; File myFile; HaiGui(Subject subject , String fileName){ this.subject = subject; subject.addObserver(this); //使当前实例成为subject所引用的具体主题的观察者 myFile = new File(fileName); } public void hearTelephone(String heardMess) { try{ boolean boo = heardMess.contains("java程序员")||heardMess.contains("软件"); if(boo){ 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); } else{ System.out.println("我是海归,这次的信息中没有我需要的信息"); } } catch(IOException exp){ System.out.println(exp.toString()); } } }
(5)具体调用实现
通过TwoApllication类来具体实现上述相关类和接口,来实现观察者模式的运用,其代码如下:
package com.liuzhen.two_observer; public class TwoApplication { public static void main(String[] args) { SeekJobCenter center = new SeekJobCenter(); //具体主题center UniversityStudent zhanglin = new UniversityStudent(center,"A.txt"); //具体观察者zhanglin HaiGui wanghao = new HaiGui(center,"B.txt"); //具体观察者wanghao center.getNewMess("腾辉公司需要10个Java程序员。"); //具体主题给出新信息 center.notifyObservers(); //具体主题通知信息 center.getNewMess("海景公司需要8个动画设计师。"); center.notifyObservers(); center.getNewMess("仁海公司需要9个电工。"); center.notifyObservers(); center.getNewMess("仁海公司需要9个电工。"); //信息不是新的 center.notifyObservers(); //观察者不会执行更新操作 } }
运行结果:
我是一个大学生,我向文件A.txt写入如下内容:
腾辉公司需要10个Java程序员。
我是海归,这次的信息中没有我需要的信息
我是一个大学生,我向文件A.txt写入如下内容:
海景公司需要8个动画设计师。
我是海归,这次的信息中没有我需要的信息
我是一个大学生,我向文件A.txt写入如下内容:
仁海公司需要9个电工。
我是海归,这次的信息中没有我需要的信息
相关推荐
总的来说,HeadFirst设计模式的学习笔记2关于观察者模式的演示,旨在帮助开发者理解如何使用观察者模式来构建可扩展的系统。通过实际的代码示例,我们可以更深入地掌握这一模式,并将其应用到日常开发中,提升代码的...
以下是对“C#设计模式学习笔记”中涉及的一些关键知识点的详细解释。 1. **设计模式的基本概念**: 设计模式是一种在特定上下文中已被证明有效的解决方案模板,它描述了如何在软件设计中解决常见问题。设计模式...
这个压缩包文件包含了23种设计模式的学习笔记和源码,旨在帮助开发者深入理解并熟练运用这些模式。以下是对每种设计模式的详细解释,以及它们在Java编程中的应用。 1. **单例模式**:确保一个类只有一个实例,并...
行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式) 2) 学习目标:通过学习,学员...
设计模式的学习不仅帮助我们编写更可维护、可扩展的代码,还能提高团队间的沟通效率,因为它们提供了通用的语言和解决方案。在实际开发中,灵活运用这些设计模式可以有效解决设计问题,提升代码质量。因此,深入理解...
"GoF 23种设计模式学习笔记" 是一个深入探讨这23个经典设计模式的资源,这些模式最初由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位作者在1994年的著作《设计模式:可复用面向对象软件的基础》中...
### Head.First 设计模式学习笔记知识点总结 #### 一、设计模式概述 设计模式是一种用于解决软件设计中常见问题的标准化方法。通过采用设计模式,开发者可以提高代码的复用性、灵活性和可维护性。《Head First 设计...
在这个“设计模式之美”的学习笔记中,我们将探讨一些主要的设计模式,以及它们在实际开发中的应用。 首先,我们从创建型模式开始。这类模式主要用于对象的创建,如单例模式(Singleton)、工厂模式(Factory ...
16. **观察者模式**(订阅者模式):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。 17. **命令模式**:将请求封装为一个对象,以便使用不同的请求、...
这份"图解java设计模式_学习笔记"是针对Java开发者深入理解和应用设计模式的重要资源。在这里,我们将深入探讨Java设计模式的核心概念、分类以及它们在实际开发中的应用。 设计模式分为三大类:创建型、结构型和...
这份"根据《JAVA与设计模式》整理的笔记及示例代码"涵盖了Java语言和设计模式的核心概念,旨在帮助开发者理解和应用这些模式。 一、设计模式的基本概念 设计模式是对在特定情境下软件设计问题的解决方案的一种描述...
设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决问题的...设计模式笔记中的内容应该涵盖了以上所述的各种模式,通过深入学习和实践,你可以将这些模式应用到实际项目中,提升自己的编程技能和设计能力。
以下是一些在尚学堂300Java设计模式部分学习笔记中涉及的设计模式的知识点: 创建型模式: 创建型模式主要解决对象创建的问题,确保系统的灵活性和封装创建细节。学习笔记中提到了5种创建型模式: 1. 单例模式...
### 设计模式学习笔记 #### 引言 设计模式(Design Patterns)是在软件设计领域内广泛应用的一种实践指南,它提供了一系列解决常见问题的方案。设计模式可以被理解为面向对象软件设计的经验总结,是对特定面向对象...
### 23种设计模式学习笔记 #### 一、软件设计模式的概念与意义 **概念:** 软件设计模式(Software Design Pattern),又称设计模式,是一套被广泛采用、经过整理和分类的代码设计经验总结。它针对软件设计过程中...
### 设计模式学习笔记 #### 一、设计模式概述 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。设计...
根据给定的信息“图解设计模式,结城浩著学习笔记”,我们可以推断出这份文档主要涉及了设计模式的学习和理解。《图解设计模式》是一本由日本著名程序员结城浩撰写的书籍,该书以图形化的方式深入浅出地讲解了软件...