观察者模式是一种常见的设计模式,也称作发布-订阅模式。它主要解决了对象之间的通知依赖关系问题。在这种模式中,一个对象(称作Subject)维护着一个对象列表,这些对象(称作Observers)都需要被通知来响应某些事件。
观察者模式的好处在于它创建了松耦合的对象之间的一对多关系,使得Subject和Observers之间的耦合度降低。在Java中,通过定义接口和抽象类等方式,可以很容易实现观察者模式。
- 观察者模式概述
观察者模式包含两个主要角色:Subject和Observer。Subject是需要被监视的对象,Observer则是负责观察Subject的变化记录并做出相应处理的对象。
当Subject发生变化时,会通知所有的Observer,并调用其相应的回调方法(也就是Observer中定义的处理Subject变化的方法)。因此,每个Observer都需要注册到Subject中去,以便Subject在发生变化时能够通知到它们。
观察者模式总体结构如下所示:
其中,Subject包含一个状态(state)和一个Observer列表(observers),它有如下几个主要方法:
-
registerObserver(Observer observer):将一个Observer对象注册到Subject中。
-
removeObserver(Observer observer):将一个Observer对象从Subject中移除。
-
notifyObservers():通知所有已经注册的Observer,以便它们做出相应的处理。
Observer接口则主要定义Observer对象中需要实现的处理Subject变化的方法。在Java中,通常将Observer接口定义为如下所示:
public interface Observer {
public void update(Object arg);
}
其中,update方法用于处理Subject发生变化时的操作。
- Java中观察者模式的实现
在Java中,实现观察者模式有多种方式。下面介绍两种比较常见的实现方式:使用Java内置类库提供的Observer和Observable类实现和使用自定义接口实现。
2.1 使用Java内置类库提供的Observer和Observable类实现
Java内置类库提供了一个Observer接口和一个Observable类,可以方便地实现观察者模式。
Observable类实际上就是Subject,它有如下方法:
-
addObserver(Observer o):注册一个Observer对象到Observable中。
-
deleteObserver(Observer o):从Observable中删除指定的Observer对象。
-
notifyObservers():通知所有已经注册的Observer,以便它们做出相应的处理。
Observer接口同上。
下面是一个使用这种方式实现观察者模式的简单示例:
import java.util.Observable;
import java.util.Observer;
public class SimpleObservable extends Observable {
private int data = 0;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
setChanged(); // 标记Subject对象的状态已发生变化
notifyObservers(data); // 通知所有已注册的Observer对象
}
}
public class SimpleObserver implements Observer {
private int data;
public void update(Observable o, Object arg) {
if (arg instanceof Integer) {
this.data = (Integer) arg;
System.out.println("Data has changed to " + this.data + " in SimpleObserver.");
}
}
}
public class Test {
public static void main(String[] args) {
SimpleObservable observable = new SimpleObservable();
SimpleObserver observer = new SimpleObserver();
observable.addObserver(observer);
observable.setData(1);
observable.setData(2);
observable.setData(3);
}
}
这个示例中,SimpleObservable类继承了Observable,并在setData方法中使用了setChanged和notifyObservers方法,标记Subject对象的状态已发生变化并通知所有已注册的Observer对象。
SimpleObserver类实现了Observer接口,并在update方法中处理Subject发生变化时的操作。
最后,Test类将SimpleObservable和SimpleObserver组装起来,实现了一个简单的观察者模式示例。
需要注意的是,Java内置的Observable类有几个限制:
-
Observable是一个类而不是一个接口,这意味着你不能再继承其他类。
-
setChanged方法被定义为protected,因此你不能显式地调用这个方法。
-
Observer接口中只有一个update方法,而Observable没有额外的状态变量来描述它的内部状态,这使得Observer无法获得有关Observable的状态信息。
-
如果Observable涉及到线程安全问题,你需要在使用Observable时自己处理。
2.2 使用自定义接口实现
另一种实现观察者模式的方式是使用自定义接口,这种方式比较灵活,也可以适用于一些特定场景。
下面是一个使用这种方式实现观察者模式的简单示例:
public interface Observer {
public void update(Object obj);
}
public interface Subject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObservers(Object obj);
}
public class SimpleSubject implements Subject {
private List<Observer> observers = new ArrayList<Observer>();
private int data = 0;
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(Object obj) {
for (Observer observer : observers) {
observer.update(obj);
}
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
notifyObservers(data);
}
}
public class SimpleObserver implements Observer {
private int data;
public void update(Object obj) {
if (obj instanceof Integer) {
this.data = (Integer) obj;
System.out.println("Data has changed to " + this.data + " in SimpleObserver.");
}
}
}
public class Test {
public static void main(String[] args) {
SimpleSubject subject = new SimpleSubject();
SimpleObserver observer = new SimpleObserver();
subject.registerObserver(observer);
subject.setData(1);
subject.setData(2);
subject.setData(3);
}
}
这个示例中,Subject接口定义了三个方法:registerObserver、removeObserver和notifyObservers。SimpleSubject类实现了Subject接口,并在setData方法中调用了notifyObservers方法。
Observer接口定义了update方法,SimpleObserver类实现了Observer接口,并在update方法中处理Subject发生变化时的操作。
最后,Test类将SimpleSubject和SimpleObserver组装起来,实现了一个简单的观察者模式示例。
自定义接口的优点在于它的灵活性,能够适用于各种场景。另外,自己实现Observer模式通常需要写更多的代码,并且Observer对象可能需要自己维护许多状态信息。
- 观察者模式的优点和缺点
观察者模式具有以下优点:
-
观察者模式将Subject和Observer之间解耦,使得它们可以独立地变化或扩展,提高了系统的灵活性和可扩展性。
-
观察者模式建立了一种灵活的一对多关系,可以在任何时候添加或删除Observer对象,实现不同的业务需求。
-
当Subject发生变化时,只需要通知已经注册的Observer对象,而无需通知未注册的Observer对象,从而避免了系统产生不必要的开销。
观察者模式具有以下缺点:
-
观察者模式可能会导致系统中出现大量的细粒度对象,从而增加系统的复杂性。
-
如果Subject和Observer之间相互依赖,会导致循环依赖问题,从而导致系统崩溃。
总之,观察者模式是一种常用的设计模式,主要解决了对象之间的通知依赖关系问题。在Java中,可以使用Java内置类库提供的Observer和Observable类或者自定义接口实现观察者模式。观察者模式具有灵活性、可扩展性和提高系统松耦合度等优点,但也会带来一些复杂性和循环依赖问题。在使用观察者模式时,需要根据具体业务场景进行权衡和选择。