观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。 这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。
让主题和观察者之间松耦合
UML图为:
Subject类
public class Subject {
private List<Observer> list = new ArrayList<>();
private String
public String getData() {
return data;
}
//添加观察者
public void attach(Observer observer){
list.add(observer);
}
//删除观察者
public void detach(Observer observer){
list.remove(observer);
}
//通知
public void notifyObservers(String data){
this.data = data;
for (Observer observer : list) {
observer.update(data);
}
}
}
Observer接口:
public interface Observer {
void update(String data);
}
具体实现类:
public class Teacher extends Subject{
public void sendHomework(String data){
notifyObservers(data);
}
}
public class Student implements Observer{
private int num;
public Student(int num) {
this.num = num;
}
@Override
public void update(String data) {
System.out.println("Student" + num + " get homework:" + data);
}
}
测试类:
public class Test {
public static void main(String[] args) {
Teacher teacher = new Teacher();
for (int i = 0; i < 5; i++) {
Student student = new Student(i);
teacher.attach(student);
}
teacher.notifyObservers("coding");
}
}
输出:
Student0 get homework:coding
Student1 get homework:coding
Student2 get homework:coding
Student3 get homework:coding
Student4 get homework:coding
二、java内置的观察者模式
在java.util库里,提供了一个Observable类以及一个Observer接口,对观察者模式进行支持
举个例子,老师给学生们发布作业
class Teacher extends Observable{
private String data;
public String getData() {
return data;
}
public void sendHomework(String data){
this.data = data;
setChanged();//状态发生改变
notifyObservers(data);
}
}
class Student implements Observer{
private int num;
public Student(int num) {
this.num = num;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("Student" + num + " get homework:" + arg);
}
}
这是观察者模式中的推模式
推模型和拉模型
推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
下面是拉模式:
class Teacher extends Observable{
private String data;
public String getData() {
return data;
}
public void sendHomework(String data){
this.data = data;
setChanged();
notifyObservers();//通知
}
}
class Student implements Observer{
private int num;
public Student(int num) {
this.num = num;
}
@Override
public void update(Observable o, Object arg) {
System.out.println("Student" + num + " get homework:" + ((Teacher)o).getData());//拉出数据
}
}
Observable类
package java.util;
public class Observable {
private boolean changed = false;//设置是否有发生改变
private Vector<Observer> obs;//ector相比于ArrayList来说,它是线程安全的,
//如果在迭代的时候删除了某个监听者就会造成错误
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
//添加观察者
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
//删除观察者
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
//通知
Object[] arrLocal;
synchronized (this) {
if (!changed)//如果没有改变就返回,不通知
return;
arrLocal = obs.toArray();//将Vector转换成数组
clearChanged();//重置
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
Observer接口
public interface Observer {
void update(Observable o, Object arg);//更新
}
java.util.Observerable有一些问题,首先它是一个类,所以必须设计一个类来继承它,但是如果某类同时具有Observable类和另一个超类的行为,就不行了,因为java不支持多重继承,没有Observable接口,所以无法建立自己的实现。
Observable将关键的方法保护起来,setChange()方法被保护(定义为protected),只有继承Observable才能创建Observable实例并组合到自己的对象中,违反了设计原则“多用组合,少用继承”