观察者模式
定义:一个对象(subject)被其他多个对象(observer)所依赖。则当一个对象变化时,发出通知,其它依赖该对象的对象都会收到通知,并且随着变化。
使用场景1:声音报警器和闪光灯报警器分别订阅热水器温度,热水器温度过高时,发出通知,两个报警器分别发声、闪光以实现报警。
使用场景2:多人订阅微信公众号,该公众号有更新文章时,自动通知每个订阅的用户。
1. 自定义观察者模式实现
定义Subject接口
public interface Subject {
// 增加观察者
public void addObserver(Observer o);
// 删除观察者
public void removeObserver(Observer o);
// 通知所有观察者
public void notifyAllObserver();
// 发生的一些改变
public void changed();
}
被观察对象(实现Subject接口)
import java.util.ArrayList;
public class MySubject implements Subject {
// 保存观察者的数据结构
private ArrayList<Observer> list = new ArrayList<Observer>();
@Override
public void addObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
list.remove(o);
}
@Override
public void notifyAllObserver() {
for (Observer observer : list) {
observer.update();
}
}
@Override
public void changed() {
// 观察的对象MySubject发生变化,通知所有的观察者
System.out.println("MySubject发生变化。。。");
notifyAllObserver();
}
}
定义观察者接口
public interface Observer {
public void update();
}
定义两个观察者(实现Observer接口)
public class Observer1 implements Observer {
@Override
public void update() {
System.out.println("观察者1,收到信息,做出相应的改变。。。");
}
}
public class Observer2 implements Observer {
@Override
public void update() {
System.out.println("观察者2,收到信息,做出相应的改变。。。");
}
}
测试
public class ObserverPatternTest {
public static void main(String[] args) {
Subject sub = new MySubject();
Observer o1 = new Observer1();
Observer o2 = new Observer2();
// 注册或订阅这两个对象
// 注册顺序决定通知顺序,最先注册的最先通知,类似于队列,与jdk内置的观察者刚好相反
sub.addObserver(o1);
sub.addObserver(o2);
// 被观察的对象sub发生改变,通知所有的观察者
sub.changed();
// 移除某个观察者
sub.removeObserver(o1);
// 再次通知所有观察者
sub.changed();
}
}
运行结果(注意通知观察者的先后顺序)
2.使用JDK内置类、接口实现观察者模式
定义被观察者对象(继承Observable类)
import java.util.Observable;
public class JdkSubject extends Observable {
private int property1;
private int property2;
// 定义内部类,用于传送数据
class Data {
private int property1;
private int property2;
public Data() {
}
public Data(int property1, int property2) {
this.property1 = property1;
this.property2 = property2;
}
public int getProperty1() {
return property1;
}
public int getProperty2() {
return property2;
}
}
// 设置数据
public void setData(int proprety1, int property2) {
this.property1 = proprety1;
this.property2 = property2;
// 有数据变化,通知所有的观察者
changed();
}
public void changed() {
// 表示数据是由更新的,数据变化了,必须调用此方法,才能去通知观察者
setChanged();
// 通知观察者时,把信息传给观察者
notifyObservers(new Data(getProperty1(), getProperty2()));
}
public int getProperty1() {
return property1;
}
public void setProperty1(int property1) {
this.property1 = property1;
}
public int getProperty2() {
return property2;
}
public void setProperty2(int property2) {
this.property2 = property2;
}
}
定义两个观察者(实现Observer接口(JDK内置接口))
import java.util.Observable;
import java.util.Observer;
import design_pattern.observer_pattern.jdkImplement.JdkSubject.Data;
public class JdkObserver1 implements Observer {
// 要改变的两个属性
private int property1;
private int property2;
@Override
public void update(Observable o, Object arg) {
this.property1 = ((Data) (arg)).getProperty1();
this.property2 = ((Data) (arg)).getProperty2();
display();
}
public void display() {
System.out.println("观察者1,收到消息,并改变数据");
System.out.println("观察者1--property1: " + property1);
System.out.println("观察者1--property2: " + property2);
}
}
import java.util.Observable;
import java.util.Observer;
import design_pattern.observer_pattern.jdkImplement.JdkSubject.Data;
public class JdkObserver2 implements Observer {
// 要改变的两个属性
private int property1;
private int property2;
@Override
public void update(Observable o, Object arg) {
this.property1 = ((Data) (arg)).getProperty1();
this.property2 = ((Data) (arg)).getProperty2();
display();
}
public void display() {
System.out.println("观察者2,收到消息,并改变数据");
System.out.println("观察者2--property1: " + property1);
System.out.println("观察者2--property2: " + property2);
}
}
测试
import java.util.Observer;
public class JdkObserverPatternTest {
public static void main(String[] args) {
// 被观察的对象
JdkSubject sub = new JdkSubject();
// 两个观察者
Observer o1 = new JdkObserver1();
Observer o2 = new JdkObserver2();
// 注册或订阅两个观察者
// 注册顺序决定通知顺序,jdk中内置的观察者是:最先注册的最晚通知,类似于栈
sub.addObserver(o1);
sub.addObserver(o2);
// 被观察对象发生改变,通知观察者做出改变
sub.setData(11, 22);
// 移除一个观察者,再去通知
sub.deleteObserver(o1);
sub.setData(33, 44);
}
}
运行结果(注意通知观察者的先后顺序)