理解
当我们在打团队游戏时,当你受到攻击需要队友帮忙时该怎么办?
这时候就需要给你所有的队友发送一条你正在被攻击的消息。所有的队友会根据你发送的消息作出相应的动作。比如有团队意识来帮你,或者不帮你继续玩自己的。
这里面的队员就是该设计模式名字中的观察者。那么受到攻击的自己的是什么呢。被观察者?不,准确的我们称之为目标或者主题。
所以整个流程大概就是:当目标(主题)的状态发生改变时就会通知观察者,观察者根据自己的情况做出相应的动作。
观察者模式主要角色组成
抽象主题角色
把所有观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者角色,一般用一个抽象类或接口来实现。
抽象观察者角色
为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色
在具体主题内部状态改变时,给所有登记过的观察者发出通知,具体主题角色通常用一个子类实现。
具体观察者角色
该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调,如果需要,具体观察者角色可以有一个指向具体主题角色的引用,通常用一个子类实现
例子
/**
* 抽象观察者
*/
public interface AbstractObserver {
public void update();
}
/**
* 抽象主题
*/
public interface AbstractSubject {
public void addObserver(AbstractObserver observer);
public void removeObserver(AbstractObserver observer);
public void notification();
}
/**
* 具体主题
*/
public class ConcreteSubject implements AbstractSubject{
private List<AbstractObserver> observers=new ArrayList<>();
@Override
public void addObserver(AbstractObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(AbstractObserver observer) {
observers.remove(observer);
}
@Override
public void notification() {
for (AbstractObserver observer:observers) {
observer.update();
}
}
}
测试类
public static void main(String[] args) {
AbstractSubject subject=new ConcreteSubject();
subject.addObserver(new AbstractObserver() {
@Override
public void update() {
System.out.println("A同学去上课了!");
}
});
subject.addObserver(new AbstractObserver() {
@Override
public void update() {
System.out.println("B同学谈恋爱了!");
}
});
subject.addObserver(new AbstractObserver() {
@Override
public void update() {
System.out.println("C同学被叫到办公室了!");
}
});
subject.notification();
}
关键代码就是通过一个ArrayList保存观察者。
Java内置的观察者模式框架
java内置观察者模式框架提供了类Observable与接口Observer:
类Observable对应抽象主题角色,内部维护Vector集合来存储具体观察者角色,接口Observer对应抽象观察者角色。
//具体主题角色
public class Watched extends Observable {
//状态改变的时候调用已注册的观察者的update方法,让它们更新自己
public void count(int number) {
for (; number >= 0; number--) {
try {
Thread.sleep(1000);
//告知变更
setChanged();
//通知所有与我相关的Observer
notifyObservers(number);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//具体观察者角色:
public class Watcher implements Observer {
//当主题角色事件触发时,会调用所有已注册的具体观察者角色的update方法
@Override
public void update(Observable o, Object arg) {
int number = (Integer) arg;
System.out.println(number);
}
}
测试类:
public static void main(String[] args) {
#创建主题角色
Watched watched = new Watched();
#创建观察者角色
Observer watcher1 = new Watcher();
#自实现
Observer watcher2 = new Observer() {
@Override
public void update(Observable o, Object arg) {
int number = (Integer) arg;
if (0 == number) {
System.out.println("done");
}
}
};
watched.addObserver(watcher1);
watched.addObserver(watcher2);
watched.count(10);
}
注意:
- 被观察者要继承Observable类
- 被观察者通知观察者时,也就是调用notifyObservers方法时一定要先调用setChanged()方法,该方法作用是将对象里面的changed这个boolean变量设为true,因为notifyObservers要首先检查该变量是否为true,如果为false就不执行而直接返回了。
扩展
Observer和Observable在Java 9标记为废弃,Observer和Observable有几个原因:
Observable没有实现Serializable接口,它的内部成员变量都是私有的,子类不能通过继承它来对Observable的成员变量处理。所以子类也不能序列化。
在 java.util.Observable文档里没有强制要求Observable是线程安全的,它允许子类覆盖重写Observable的方法,事件通知无序以及事件通知发生在不同的线程里,这些都是会影响线程安全的问题。
例如,只是支持事情发生变化的概念,但是不能提供更多哪些内容发生了改变。
替代
可以使用java.beans 里的PropertyChangeEvent 和 PropertyChangeListener 来代替目前Observer和Observable的功能。