前言
在设计模式演化之观察者模式1
中,我们实现了一个经典的观察者模式,下边继续对观察者模式进行优化,以便于能够在各种场景下更好的工作。
优化
1.我们在Subject中新增多个属性。然后一下Subject类的名字,使它更符合业务场景。现在我们要观察一个User类多个属性的变化。
public class User {
private String name;
private int age;
private String address;
}
此时,你会发现按照前面观察者模式的写法麻烦就来了。之前,为了能让多个对象观察name属性的变化,我们专门定义个了一个Observer接口,并提供了它的实现类。如果新增的属性也按照这个模式去定义,那观察这个类的代价就太大了。显然经典模式的写法,不足以应对这种观察多个属性的情况。
你可能会想,能不能将这些被观察的属性也抽象出一个公共的接口Observable(注意不是Observer),让被观察的属性类实现这个接口来表示它是一个可观察对象呢?很遗憾,答案是否定的。
- 首先,抽象之后会造成属性的类型丢失,这对观察它变化的类来说是不可行的。抽象之后所有的属性都变成了Observable类型了。
- 要让被观察属性实现Observable接口,就需要去改这些属性类的源码,没有源码自然就改不了了。如第三库中的类。
- 对于基本类型和String类型,我们无法让它们去实现这个抽象出来的接口。
此时,我们也可以得出观察多个属性时需要的基本要求
- 被观察属性必须具备统一的通知观察者刷新的方法——onChange()。这样可以使得观察者只需要Observer接口就可以,观察该对象
- 被观察的属性不能丢时类型,且通知观察者刷新时,必须在onChange()中传递准确的类型
- 不得改动被观察属性类的源码
既然修改被观察属性的类源码行不通,那我们就考虑给它们包装一层,并在包装类里去调用onChange()方法,这样它们就可以具有统一的行为。然后为了保证属性类型不丢失,我们可以使用泛型来保存实际被观察的属性类型,当调用onChange()时,将实际类型传递出去。这里就要求onChange()方法也具备接收泛型的能力,因此还需要对Observer也做出相应的修改。代码如下
public class Observable<T> {
private T value;
private final List<Observer<T>> observers = new ArrayList<>();
// 改一下方法名,使含义更突出。实际就是注册观察者的功能
public void observe(Observer<T> observer) {
observers.add(observer);
}
public void unregisterObserver(Observer<T