还要做什么?
在教你写响应式框架(一)中我们介绍了观察者模式,现在我们将基于上一篇中的代码进行改造。当然,我们是有目的的改造:
- 在响应式框架中,观察者是可能随时产生,种类多,生命周期却短暂.
- 我们希望操作是异步的,并且只有在观察者被注册到被观察者上时,被观察者才生效.
在开始改造之前,为了避免没看过上一篇的童鞋产生断裂感,我仍然先贴一下观察者的实现,为了从能够”望文生义”,其中有一些小细节我做了调整:
//被观察者
public abstract class Observable {
private List<Observer> list = new ArrayList<>();
public void attach(Observer observer) {
list.add(observer);
}
public void detach(Observer observer) {
list.remove(observer);
}
public void notifyObservers(String newState) {
list.stream().forEach(ob->{ob.update(newState);});
}
}
//被观察者的具体实现
public class ConcreteObservable extends Observable {
public void change(String state) {
this.notifyObservers(state);
}
}
//观察者接口
public interface Observer {
void update(String state);
}
//观察者的具体实现
public class ConcreteObserver implements Observer {
@Override
public void update(String state) {
System.out.println("主题状态改变了:" + state);
}
}
//客户端测试代码
public class Client {
public static void main(String[] args) {
ConcreteObservable subject = new ConcreteObservable();
subject.attach(new Observer() {
@Override
public void update(String state) {
System.out.println("主题状态变化:" + state);
}
});
subject.change("2");
}
}
别样的观察者模式
针对上面提到的第一个需求,我们很容易理解,只提供给用户相关的接口就行,具体实现由用户根据实际情况来实现.
那如何实现第二个需求呢?暂时我们先不说,直接从代码中看实现:
//被观察者
public class Observable {
protected OnAttach onAttach;
private Observable() {
}
public Observable(OnAttach onAttach) {
this.onAttach = onAttach;
}
public void attach(Observer observer) {
onAttach.call(observer);
}
public interface OnAttach {
void call(Observer observer);
}
}
//观察者
public interface Observer {
void update(String state);
}
//客户端代码
public class Client {
public static void main(String[] args) {
Observable observable = new Observable(new Observable.OnAttach() {
@Override
public void call(Observer observer) {
observer.update("1");
}
});
observable.attach(new Observer() {
@Override
public void update(String state) {
System.out.println("state:" + state);
}
});
}
}
经过一番折磨之后,对原有的代码进行了重构,重点关注Observable类.在Observable中,我们定义OnAttach接口,该接口负责通知观察者.同时attach方法在将观察者注册到被观察者上之后,会调用OnAttach的call方法来实现自动通知,这样做的好处就是我们不需要再手动调用call方法来通知被观察者了—-对用户屏蔽细节.
为了更方便理解,我们将客户端的代码写成你所熟悉的方式:
public class Client {
public static void main(String[] args) {
//注册关系,简化了手动通知观察者的过程
Observable.OnAttach onAttach = new Observable.OnAttach() {
@Override
public void call(Observer observer) {
observer.update("1");
}
};
//被观察者
Observable observable = new Observable(onAttach);
//观察者
Observer observer = new Observer() {
@Override
public void update(String state) {
System.out.println("state:" + state);
}
};
//将观察者注册到被观察者上
observable.attach(observer);
}
}
我们发现最大的变化就是被观察者,尤其是通过OnAttach接口来实现自动通知,现在我们分析一下:
首先,我们实现OnAttach接口,该接口含有唯一的方法call.call方法接受一个Observer对象,此对象就是我们的观察者对象observer.当执行observable.attach(observer)方法时,会引起call方法的调用,进而执行observer.update(“1”),然后执行System.out.println(“state:” + state);,不难发现这就是标准观察者模式的变种.
重构,改善原有设计
分析完之后,我们再看一下代码,哇,好low,这么低级的代码看起来像坨大便一样.既然要作为一个框架,必然要尽可能的通用和易于理解.因此我们在上面代码的基础上修改两点:
- 引入泛型
- 用静态工厂方法代替构造器.
引入泛型想必每个人都能理解,但是用静态工厂可能有些人觉得多此一举了,对此请各位自行查阅Joshua Bloch大神的<>的第一节吧.
重构后的代码:
//被观察者
public class Observable<T> {
protected OnAttach onAttach;
public Observable(OnAttach onAttach) {
this.onAttach = onAttach;
}
public static <T> Observable<T> create(OnAttach<T> onAttach) {
return new Observable(onAttach);
}
public void attach(Observer<T> observer) {
onAttach.call(observer);
}
public interface OnAttach<T> {
void call(Observer<? super T> observer);
}
}
//观察者
public interface Observer<T> {
void update(T state);
}
//客户端代码
public class Client {
public static void main(String[] args) {
//注册关系,简化了手动通知观察者的过程
Observable.OnAttach onAttach = new Observable.OnAttach() {
@Override
public void call(Observer observer) {
ArrayList<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
observer.update(list);
}
};
//被观察者
Observable observable = Observable.create(onAttach);
//观察者
Observer observer = new Observer<ArrayList<Integer>>() {
@Override
public void update(ArrayList<Integer> state) {
state.stream().forEach(p -> {
System.out.println(p);
});
}
};
//将观察者注册到被观察者上
observable.attach(observer);
}
}
现在的代码看起来是不是好一点了?到现在,你可能会说:压根没什么用嘛.对的,起码到目前来说,并没有什么用.在下一节中,我们将引入操作符,这才是我们关注的重点.
完整项目可见EasyReactive