教你写响应式框架(二)
来源:互联网 发布:红外预警卫星 算法 编辑:程序博客网 时间:2024/06/18 09:39
还要做什么?
在教你写响应式框架(一)中我们介绍了观察者模式,现在我们将基于上一篇中的代码进行改造。当然,我们是有目的的改造:
- 在响应式框架中,观察者是可能随时产生,种类多,生命周期却短暂.
- 我们希望操作是异步的,并且只有在观察者被注册到被观察者上时,被观察者才生效.
在开始改造之前,为了避免没看过上一篇的童鞋产生断裂感,我仍然先贴一下观察者的实现,为了从能够”望文生义”,其中有一些小细节我做了调整:
//被观察者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
- 教你写响应式框架(二)
- 教你写响应式框架(三)
- 教你写响应式框架(一)
- 教你写响应式框架(四)
- 教你写响应式框架(一)
- 教你写Http框架(二)——三个例子带你深入理解AsyncTask
- Android开发之手把手教你写ButterKnife框架(二)
- 教你写Http框架(一)
- 教你写Http框架(三)
- FreeCodeCamp 学习笔记(二)响应式框架bootstrap
- 手把手教你写《雷神》游戏(二)
- 教你写Android网络框架
- 教你写Android ImageLoader框架
- 自己写一个MVC框架(二)
- 写框架思路进程(二)
- 自己动手写PHP框架(二)
- Android 框架炼成 教你如何写组件间通信框架EventBus(三)
- 响应式开发(二)-----Bootstrap框架的介绍
- Java day03 进制转换(2)索引表 数组实现
- android sdk 下载
- E96系列电阻代码表
- 获取手机内存大小以及获取SD卡内存大小
- Java day03 进制转换(3)索引表 数组实现 十进制向各进制转换
- 教你写响应式框架(二)
- JavaScript基础篇(三)— — DOM事件揭秘
- 宏的用法与简介
- Cutecom--Linux下串口调试工具
- [LeetCode]213 强盗入屋 II
- [CodeForces 126C]E-reader Display[实现]
- Leetcode #10 Regular Expression Matching 正则表达式匹配 解题小节
- 初次写博客
- 图型dp csu1700 Black Company