在软件系统中,当一个对象的行为依赖另外一个对象的状态时,观察者模式就很有用。若不使用观察者模式,实现类似的功能,需要在一个线程中不断监听对象状态的变化。
在一个复杂的系统中,可能会因此开启很多线程,这将使系统性能产生额外的负担。

观察者模式的意义也在于此,它可以在单线程中,在自身状态发生变化时,及时通知所依赖的对象。

以下使用一个例子来说明。
AbstractSubject抽象主题对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 抽象主题类。模拟在修改主题的text属性时,通知所有观察者。
 * Created by j.tommy on 2017/9/15.
 */
public abstract class AbstractSubject {
    // 主题属性
    String text;
    // 添加观察者
    public abstract void addObserver(IObserver observer);
    // 删除观察者
    public abstract void removeObserver(IObserver observer);
    // 通知所有观察者
    abstract void inform();
    // 设置主题属性
    public abstract void setText(String text);
}

具体主题对象ConcreteSubject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * Created by j.tommy on 2017/9/15.
 */
public class ConcreteSubject extends AbstractSubject {
    private final Vector<IObserver> observers = new Vector<IObserver>();
    public void addObserver(IObserver observer) {
        if (null != observer) {
            observers.addElement(observer);
        }
    }
    public void removeObserver(IObserver observer) {
        if (null != observer) {
            observers.removeElement(observer);
        }
    }
    void inform() {
        Event event = new Event();
        event.setMsg(text);
        // 通知所有观察者
        for (IObserver observer : observers) {
            observer.changeEvent(event);
        }
    }
    // 设置主题属性,并通知所有观察者
    public void setText(String text) {
        this.text = text;
        System.out.println(this.getClass().getName() + " setText. Text is [" + text + "].");
        inform();
    }
}

在具体的观察者实现类中,维护了一个观察者队列,并提供了添加和删除观察者的方法。在自身状态(text属性)发生变化时,通知所有观察者。

观察者接口对象IObserver

1
2
3
4
5
6
7
8
/**
 * 观察者接口。
 * Created by j.tommy on 2017/9/15.
 */
public interface IObserver {
    // 给主题回调的方法
    public void changeEvent(Event event);
}

具体的观察者ConcreateObserver

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Created by j.tommy on 2017/9/15.
 */
public class ConcreateObserver implements IObserver {
    private String name;
    public ConcreateObserver(String name) {
        this.name = name;
    }
    @Override
    public void changeEvent(Event event) {
        System.out.println(this.name + " received subject event. msg=" + event.getMsg());
    }
}

主题对象属性text发生变化时,通知观察者的方法参数Event

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * Created by j.tommy on 2017/9/15.
 */
public class Event {
    private String msg;
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * Created by j.tommy on 2017/9/15.
 */
public class Main {
    public static void main(String[] args) {
        // 构造一个主题
        AbstractSubject subject = new ConcreteSubject();
        // 添加2个观察者
        subject.addObserver(new ConcreateObserver("observer-1"));
        subject.addObserver(new ConcreateObserver("observer-2"));
        // 对主题对象的一个属性设值
        subject.setText("hello");
        System.out.println("==================");
        subject.setText("你好");
    }
}

测试结果:

观察者模式如此常用,以至于JDK内部就为我们开发人员提供了一套观察者模式的实现。
在java.util包中,包括Observable类和Observer接口。
在Observable中,已经实现了主要的功能,包括添加观察者、删除观察者、通知观察者。
在Observer接口中,定义了update方法,它会在Observable中的nofityObservers方法中被调用,以获得最新的状态变化。
我们只需要继承Observable、并实现Observer接口即可。

下面仍然是实现上面例子的功能,但这里使用JDK提供的Observable和Observer。
具体主题类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * Created by j.tommy on 2017/9/15.
 */
public class MyJdkObservable extends Observable {
    private String name;
    public void setName(String name) {
        this.name = name;
        this.setChanged();
        this.notifyObservers();
    }
    public String getName() {
        return this.name;
    }
}

具体观察者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * Created by j.tommy on 2017/9/15.
 */
public class MyJdkObserver implements Observer {
    private String name;
    public MyJdkObserver(String name) {
        this.name = name;
    }
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof MyJdkObservable) {
            MyJdkObservable myJdkObservable = (MyJdkObservable) o;

            System.out.println(this.name + " received event.MyJdkObservable.name=" + myJdkObservable.getName());
        }
    }
}

测试代码:

1
2
3
4
5
6
MyJdkObservable myJdkObservable = new MyJdkObservable();
myJdkObservable.addObserver(new MyJdkObserver("observer-1"));
myJdkObservable.addObserver(new MyJdkObserver("observer-2"));
myJdkObservable.setName("hello");
System.out.println("===================");
myJdkObservable.setName("你好");

测试结果:

在JDK中,观察者模式也得到的普遍的应用。一个典型的例子就是JButton。JButton继承自AbstractButton,AbstractButton中维护着一组监听器,它们就扮演着观察者的角色。

参考《Java程序性能优化-让你的Java程序更快、更稳定》(葛一宁等编著)。