当一个对象的状态放生改变的时候,如何让依赖于它的所有对象得到通知,并进行相应的处理?
Subject:目标对象,通常具有以下功能
Observer:定义观察者接口,提供目标通知时对应的更新方法,这个更新方法进行相应的业务逻辑处理,可以在这个方法回调目标对象,以获取目标对象的数据
ConcreteSubject:具体的目标对象,用来维护目标的状态,当目标状态发生改变时,通知所有注册有效的观察者,让观察者执行相应的处理
ConcreteObserver:观察者的具体对象,用来接收目标的通知,并进行相应的后续处理
// Subject:public class Subject {
//注意:Arraylist里面可以添加null元素
private List<Observer> readers = new ArrayList<>(); public void attach(Observer reader){ if(reader != null){
readers.add(reader);
}
} public void detach(Observer reader){ if(reader != null){
readers.remove(reader);
}
} public void notifyAllReaders(){ if(readers.size() != 0){ //通过流的方式来访问
//因为是从Newapaper方法里调用,所有this表示Newspaper实例
readers.forEach(reader -> reader.update(this));
}
}
}//Newspaper:public class Newspaper extends Subject{
private String content; public String getContent(){ return content;
} //维护目标的状态
public void setContent(String content){ //内容更新之后通知所有观察者
this.content = content;
notifyAllReaders();
}
}// Observer:public interface Observer {
public void update(Subject subject);
}// Reader:public class Reader implements Observer {
private String name; public void setName(String name) { this.name = name;
} public String getName() { return name;
} @Override
public void update(Subject subject) {
System.out.println(name + "收到了报纸\n 报纸的内容为: "
+ ((Newspaper)subject).getContent() );
}
}//Client端public class Client {
public static void main(String[] args) { //创建一个报纸,作为被观察者
NewsPaper subject = new NewsPaper(); //创建阅读者,也就是观察者
Reader reader1 = new Reader();
reader1.setName("张三");
Reader reader2 = new Reader();
reader2.setName("李四");
Reader reader3 = new Reader();
reader3.setName("王五"); //注册阅读者
subject.attach(reader1);
subject.attach(reader2);
subject.attach(reader3); //要出报纸啦
subject.setContent("本期内容是观察者模式");
}
}
观察者模式的定义: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式把多个订阅者称为观察者Observer,多个观察者观察的对象的被称为目标Subject。
一个目标可以有任意多个观察者对象,一旦目标的状态发生改变时,所有注册的观察者就会得到通知,然后各个观察者会对通知作出相应的处理,执行相应的业务功能处理,并使自己的状态和目标对象的状态保持一致。
观察者模式的本质:触发联动
Swing中的观察者模式:Swing组件是被观察的目标,而每个实现监听的类就是观察者,监听器的接口就是观察者的接口,在调用addXXXListener方法的时候就相当于注册观察者。当组件被单击时,状态发生改变的时候,就会产生相应的通知,会调用注册的观察者的方法,就是我们所实现的监听器的方法。
扩展:区别对待观察者
/**
* 定义水质监测的目标对象
*/public abstract class WaterQualitySubject {
/**
* 用来保存注册的观察者对象
*/
protected List<WatcherObserver> observers = new ArrayList<WatcherObserver>(); /**
* 注册观察者对象
* @param observer 观察者对象
*/
public void attach(WatcherObserver observer) {
observers.add(observer);
} /**
* 删除观察者对象
* @param observer 观察者对象
*/
public void detach(WatcherObserver observer) {
observers.remove(observer);
} /**
* 通知相应的观察者对象
*/
public abstract void notifyWatchers(); /**
* 获取水质污染的级别
* @return 水质污染的级别
*/
public abstract int getPolluteLevel();
}/**
* 具体的水质监测对象
*/public class WaterQuality extends WaterQualitySubject{
/**
* 污染的级别,0表示正常,1表示轻度污染,2表示中度污染,3表示高度污染
*/
private int polluteLevel = 0; /**
* 获取水质污染的级别
* @return 水质污染的级别
*/
public int getPolluteLevel() { return polluteLevel;
} /**
* 当监测水质情况后,设置水质污染的级别
* @param polluteLevel 水质污染的级别
*/
public void setPolluteLevel(int polluteLevel) { this.polluteLevel = polluteLevel; //通知相应的观察者
this.notifyWatchers();
} /**
* 通知相应的观察者对象
*/
public void notifyWatchers() { //循环所有注册的观察者
for(WatcherObserver watcher : observers){ //开始根据污染级别判断是否需要通知,由这里总控
if(this.polluteLevel >= 0){ //通知监测员做记录
if("监测人员".equals(watcher.getJob())){
watcher.update(this);
}
} if(this.polluteLevel >= 1){ //通知预警人员
if("预警人员".equals(watcher.getJob())){
watcher.update(this);
}
} if(this.polluteLevel >= 2){ //通知监测部门领导
if("监测部门领导".equals(watcher.getJob())){
watcher.update(this);
}
}
}
}
}/**
* 水质观察者接口定义
*/public interface WatcherObserver {
/**
* 被通知的方法
* @param subject 传入被观察的目标对象
*/
public void update(WaterQualitySubject subject); /**
* 设置观察人员的职务
* @param job 观察人员的职务
*/
public void setJob(String job); /**
* 获取观察人员的职务
* @return 观察人员的职务
*/
public String getJob();
}/**
* 具体的观察者实现
*/public class Watcher implements WatcherObserver{
/**
* 职务
*/
private String job; public void update(WaterQualitySubject subject) { //这里采用的是拉的方式
System.out.println(job+"获取到通知,当前污染级别为:"+subject.getPolluteLevel());
} public String getJob() { return this.job;
} public void setJob(String job) { this.job = job;
}
}public class Client {
public static void main(String[] args) { //创建水质主题对象
WaterQuality subject = new WaterQuality(); //创建几个观察者
WatcherObserver watcher1 = new Watcher();
watcher1.setJob("监测人员");
WatcherObserver watcher2 = new Watcher();
watcher2.setJob("预警人员");
WatcherObserver watcher3 = new Watcher();
watcher3.setJob("监测部门领导"); //注册观察者
subject.attach(watcher1);
subject.attach(watcher2);
subject.attach(watcher3); //填写水质报告
System.out.println("当水质为正常的时候------------------〉");
subject.setPolluteLevel(0);
System.out.println("当水质为轻度污染的时候---------------〉");
subject.setPolluteLevel(1);
System.out.println("当水质为中度污染的时候---------------〉");
subject.setPolluteLevel(2);
}
}