目录
4.4 具体观察者_1 : UniversityStudent.java
1. 什么是观察者模式
观察者模式(别名:依赖,发布-订阅)
定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新。
2. 使用场景
在许多设计中,经常涉及到多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化。
3. 模式的结构与使用
观察者模式的结构中包括四种角色:
- 主题(Subject) 观察者(Observer)
- 具体主题(ConcreteSubject)
- 具体观察者(ConcreteObserver)
4. 简单例子
4.1 主题 : Subject.java
package indi.peter.designpattern.observerpattern;
public interface Subject {
public void addObserver(Observer o);
public void deleteObserver(Observer o);
public void notifyObservers();
}
4.2 观察者 : Obsever.java
package indi.peter.designpattern.observerpattern;
public interface Observer {
public void hearTelephone(String heardMess);
}
4.3 具体主题 : SeekJobCenter.java
package indi.peter.designpattern.observerpattern;
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);
}
@Override
public void deleteObserver(Observer o) {
if (personList.contains(o))
personList.remove(o);
}
@Override
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;
else {
mess = str;
changed = true;
}
}
}
4.4 具体观察者_1 : UniversityStudent.java
package indi.peter.designpattern.observerpattern;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class UniversityStudent implements Observer {
Subject subject;
private File myFile;
public UniversityStudent(Subject subject, String fileName) {
this.subject = subject;
subject.addObserver(this); // 使当前实例成为subject所引用的具体主题的观察者
myFile = new File(fileName);
}
@Override
public void hearTelephone(String heardMess) {
RandomAccessFile out = null;
try {
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());
}finally {
if(out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4.5 具体观察者_2 : HaiGui.java
package indi.peter.designpattern.observerpattern;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class HaiGui implements Observer {
Subject subject;
private File myFile;
HaiGui(Subject subject, String fileName) {
this.subject = subject;
subject.addObserver(this); // 使当前实例成为subject所引用的具体主题的观察者
myFile = new File(fileName);
}
public void hearTelephone(String heardMess) {
RandomAccessFile out = null;
try {
boolean boo = heardMess.contains("java程序员") || heardMess.contains("软件");
if (boo) {
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());
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.6 应用 : Application.java
package indi.peter.designpattern.observerpattern;
public class Application {
public static void main(String args[]){
SeekJobCenter center=new SeekJobCenter();
UniversityStudent zhangLin=new UniversityStudent(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();
}
}
5. 模式应用的开源框架
Spring 事件驱动模型就是观察者模式很经典的一个应用. Spring 事件驱动模型中的三种角色.
1) 事件角色
- ApplicationEvent (org.springframework.context包下)充当事件的角色,这是一个抽象类,它继承了
java.util.EventObject
并实现了 java.io.Serializable接口。
Spring 中默认存在以下事件,他们都是对 ApplicationContextEvent 抽象类的实现(继承自ApplicationContextEvent):
- ContextStartedEvent:ApplicationContext 启动后触发的事件;
- ContextStoppedEvent:ApplicationContext 停止后触发的事件;
- ContextRefreshedEvent:ApplicationContext 初始化或刷新完成后触发的事件;
- ContextClosedEvent:ApplicationContext 关闭后触发的事件。
2) 事件监听者角色
ApplicationListener 充当了事件监听者角色,它是一个接口,里面只定义了一个 onApplicationEven()
方法来处理ApplicationEvent。ApplicationListener接口类源码如下,可以看出接口定义,接口中的事件只要实现了 ApplicationEvent就可以了。所以,在 Spring中我们只要实现 ApplicationListener 接口的 onApplicationEvent() 方法即可完成监听事件
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
ApplicationEvent 和 ApplicationListener 的代码实现都非常简单,内部并不包含太多属性和方法,它们最大的作用是做类型标识之用
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened */
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
public class EventObject implements java.io.Serializable {
protected transient Object source;
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
public Object getSource() {
return source;
}
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
3) 事件发布者角色
ApplicationEventPublisher 充当了事件的发布者,它也是一个接口。
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
this.publishEvent((Object)event);
}
void publishEvent(Object var1);
}
ApplicationEventPublisher 接口的publishEvent()
这个方法在AbstractApplicationContext 类中被实现,阅读这个方法的实现,你会发现实际上事件真正是通过 ApplicationEventMulticaster 来广播出去的。
6. 模式优点
- 具体主题和具体观察者是松耦合关系。由于主题(Subject)接口仅仅依赖于观察者(Observer)接口,因此具体主题只是知道它的观察者是实现观察者(Observer)接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题(Subject)接口,因此具体观察者只是知道它依赖的主题是实现主题(subject)接口的某个类的实例,但不需要知道具体是哪个类。
- 观察模式满足“开-闭原则”。主题(Subject)接口仅仅依赖于观察者(Observer)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(Observer)接口,因此如果增加新的实现观察者(Observer)接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题(Observer)接口,如果增加新的实现主题(Subject)接口的类,也不必修改创建具体观察者类的代码。
富贵必从勤苦得,男儿须读五车书。加油少年郎!!!