1.什么是观察者模式
定义对象间的一种一对多的关系,当一个对象的状态发生改变的时候,所有依赖于它的其他对象都将得到通知并自动更新。
2.观察者模式结构中的四种角色
抽象主题(Subject):抽象主题是一个接口(或类或抽象类),该接口规定了具体主题需要实现的方法。
抽象观察者(Observer):抽象观察者是一个接口(或类或抽象类),该接口规定了具体观察者用来更新数据的方法。
具体主题(ConcreteSubject):具体主题是实现(继承)抽象主题接口的一个实例,存放观察者对象,当状态发生改变的时候,通知各个观察者。
具体观察者(ConcreteObserver):具体观察者是实现(继承)抽象观察者接口的实例,存放有关状态。
3.观察者模式的优点
①.观察者模式在被观察者和观察者之间建立一个抽象的耦合。主题角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。主题并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
②.观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。
4.观察者模式的缺点
①.如果一个主题有很多观察者观察,那么当主题改变的时候,通知所有的观察者会花费很多的时间。
②.虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的
废话说了这么多,用了才知道。下面是一个奇数观察者和偶数观察者观察产生随机数的主题,并选择自己需要的数:
抽象主题:
public interface Subject {
//添加观察者
public void addObserver(Observer o);
//删除观察者
public void deleteObserver(Observer o);
//通知观察者更新
public void notifyObservers();
}
抽象观察者:
public interface Observer {
//更新方法
public void update();
}
具体主题(随机数产生类):
public class RandomNumberSubject implements Subject{
//用来存储具体观察者对象
private ArrayList<Observer> observers = new ArrayList<>();;
//产生的随机数
private int number;
@Override
public void addObserver(Observer o) {
if(!(observers.contains(o))){
observers.add(o);
}
}
@Override
public void deleteObserver(Observer o) {
if(observers.contains(o)){
observers.remove(o);
}
}
@Override
public void notifyObservers() {
//遍历出每个观察者,并更新
for(int i = 0;i<observers.size();i++){
Observer observer = observers.get(i);
observer.update();
}
}
//产生随机数,并通知观察者更新
public void generateNum(){
//产生10个随机数
for(int i = 0;i<10;i++){
//产生10以内的随机数
Random random = new Random();
number = random.nextInt(10);
//通知观察者
notifyObservers();
}
}
//得到产生的随机数
public int getNumber(){
return number;
}
}
具体观察者1(奇数观察者):
public class ObserverOdd_number implements Observer{
//观察者所观察的主题
Subject subject;
//构造函数
public ObserverOdd_number(Subject subject){
this.subject = subject;
//添加观察者
subject.addObserver(this);
}
@Override
public void update() {
//判断是否具体主题的对象
if(subject instanceof RandomNumberSubject){
//得到产生的随机数
int number = ((RandomNumberSubject) subject).getNumber();
//选择需要的奇数
if(number%2 != 0){
System.out.println("奇数观察者所观察到的数是:"+number);
}
}
}
}
具体观察者2(偶数观察者):
public class ObserverEven_number implements Observer{
Subject subject;
public ObserverEven_number(Subject subject){
this.subject = subject;
subject.addObserver(this);
}
@Override
public void update() {
if(subject instanceof RandomNumberSubject){
int number = ((RandomNumberSubject) subject).getNumber();
if(number%2 == 0){
System.out.println("偶数观察者所观察到的数是:"+number);
}
}
}
}
测试类:
public class ObserverTest {
public static void main(String [] args){
//具体主题对象
RandomNumberSubject rn = new RandomNumberSubject();
//具体观察者
ObserverOdd_number oon = new ObserverOdd_number(rn);
ObserverEven_number oen = new ObserverEven_number(rn);
//调用产生随机数的方法
rn.generateNum();
}
}
结果:
奇数观察者所观察到的数是:5
偶数观察者所观察到的数是:4
偶数观察者所观察到的数是:8
奇数观察者所观察到的数是:9
偶数观察者所观察到的数是:6
奇数观察者所观察到的数是:9
偶数观察者所观察到的数是:0
偶数观察者所观察到的数是:4
奇数观察者所观察到的数是:3
偶数观察者所观察到的数是:8
测试类中只是调用了具体主题产生随即数的方法,各个观察者就随之更新了自己的状态。
当然也可以有一个观察者依赖多主题,只是多了一个具体主题类,只需要在观察者类中得到相关信息,然后根据自己的要求更新自己就可以了。这个不再多说。
其实java自己也提供了相关的类和接口供我们实现观察者模式,在java.util包中,提供了Observable类和Observer接口。其实Observable类就相当于主题接口,继承Observable的子类实例就是一个主题;Observer接口就是抽象观察者,实现该接口的类实例就是一个观察者。只是Observable类是用Vector(在集合框架中分析了Vector和ArrayList的区别)来存放具体观察者,其他都是一样的,所以不多说,感兴趣的同学可以自己查API,然后写写程序。