UniRX/Reactive 反应式编程 三元素
有关UniRX的基本概念不多说了,网上有很多反应式编程的介绍,主要元素如下:
这里主要结合源码,说明一下本人对各元素的理解
Observer
Observer 观察者,对应接口IObserver
public interface IObserver<in T>
{
void OnCompleted();
void OnError(Exception error);
void OnNext(T value);
}
用于订阅(Subscribe)被观察者的消息或者事件。一般我们不会直接使用到它,大部分我们是使用匿名函数(lambda表达式),如下都是我们常用的方法:
public static IDisposable Subscribe<T>(this IObservable<T> source)
{
return source.Subscribe(UniRx.InternalUtil.ThrowObserver<T>.Instance);
}
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext)
{
return source.Subscribe(Observer.CreateSubscribeObserver(onNext, Stubs.Throw, Stubs.Nop));
}
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action<Exception> onError)
{
return source.Subscribe(Observer.CreateSubscribeObserver(onNext, onError, Stubs.Nop));
}
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action onCompleted)
{
return source.Subscribe(Observer.CreateSubscribeObserver(onNext, Stubs.Throw, onCompleted));
}
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action<Exception> onError, Action onCompleted)
{
return source.Subscribe(Observer.CreateSubscribeObserver(onNext, onError, onCompleted));
}
其本质是创建了Observer来接收事件的。
Observable
Observable 可观察的,对应接口IObservable,被观察者具有的特性。可以认为是被观察者的抽象定义。
上图可以看到其与Observer的关系
OperatorsOperators
操作符,其本质是提供了针对Observable一系列的操作,操作的返回还是一个Observable对象,以达到串联的效果,其是LING操作的一个超集,常用的操作比如,Where、Select等。其一般是通过Observable扩展的方式对外提供的。主要在代码在./Observable
public static IObservable<T> Where<T>(this IObservable<T> source, Func<T, int, bool> predicate)
{
return new WhereObservable<T>(source, predicate);
}
可以看到其返回的还是一个Observable对象,对应的WhereObservable定义在./Operators/Where.cs中,这个目录下还有很多的操作类定义
internal class WhereObservable<T> : OperatorObservableBase<T>
{
readonly IObservable<T> source;
readonly Func<T, bool> predicate;
readonly Func<T, int, bool> predicateWithIndex;
public WhereObservable(IObservable<T> source, Func<T, bool> predicate)
: base(source.IsRequiredSubscribeOnCurrentThread())
{
this.source = source;
this.predicate = predicate;
}
自定义Operators,也基于OperatorObservableBase进行扩展。其中的核心的代码:
protected override IDisposable SubscribeCore(IObserver<T> observer, IDisposable cancel)
{
if (predicate != null)
{
return source.Subscribe(new Where(this, observer, cancel));
}
else
{
return source.Subscribe(new Where_(this, observer, cancel));
}
}
其返回一个Where对象,可以看以下的代码
public abstract class OperatorObserverBase<TSource, TResult> : IDisposable, IObserver<TSource>
{
protected internal volatile IObserver<TResult> observer;
IDisposable cancel;
public OperatorObserverBase(IObserver<TResult> observer, IDisposable cancel)
{
this.observer = observer;
this.cancel = cancel;
}
public abstract void OnNext(TSource value);
public abstract void OnError(Exception error);
public abstract void OnCompleted();
其本身是一个Observer,它的OnNext方法只是调用构造时传入的Observer对象,事件触发时会先调用Where这个观察者,内部会判断是否满足Where的条件,如果满足调用传入的Observer的OnNext的方法。
总结一下,Operator 运算符 很确切的表达设计者的思想,如果从运算符的角度出发,具有传递性,它是一个桥梁,传递性体现在代码上有两个表示,
- 一是调用的关系,比如:Observable.Start().Where().Select().Subscribe();
- 一是内部Observer的传递,整个表达式,会构建一个Observer的列表,每一级会构建一个新的Obsever加入到列表中,队列的尾部为用户真正的处理代码,即调用Subscribe函数中的内容。
Subject
Subject 目标者,只是被观察者中的常用的实体类。UniRX最强大的地方就在于,可以把好多的对象,转化为可观察的,比如:Event、Task、Function等等。。。先看ISubject的定义如下:
public interface ISubject<T> : ISubject<T, T>, IObserver<T>, IObservable<T>
{
}
这里有点让人头大,Subject是被观察者,它为啥还要实现IObserver?这里可以理解Subject是目前UniRX中唯一可以主动触发的事件发起者,而这个触发者其实是调用者本身,所以它也是一个Observer。它可以一个发动机,通过一层层Observer的传递,最终调用用户Subscribe中的Lambda表达式。
Scheduler
IScheduler 与 TaskScheduler 的关系Scheduler即定义了事件触发时Observer运行的线程环境,分为
- NewThreadScheduler:即在新线程上执行
- ThreadPoolScheduler:即在线程池中执行
- TaskPoolScheduler:与ThreadPoolScheduler类似
- CurrentThreadScheduler:在当前线程执行
- ImmediateScheduler:在当前线程立即执行
- EventLoopScheduler:创建一个后台线程按序执行所有操作
注意: 这里当前线程说明一下,当前的含义是什么?是Subscribe调用者的当前线程,还是触发者的当前线程呢?通过简单的Debug,其是指触发者的当前线程,这里比较容易引起歧义。
DefaultScheduler
有以下几个值,用于不同的时机,或者是不同的Operator
public static void SetDotNetCompatible()
{
ConstantTimeOperations = Scheduler.Immediate;
TailRecursion = Scheduler.Immediate;
Iteration = Scheduler.CurrentThread;
TimeBasedOperations = Scheduler.ThreadPool;
AsyncConversions = Scheduler.ThreadPool;
}
后续
以上只是对UniRX的理解,各语言的Rx实现大致相同。开发者应用可以参考,用起来更加直观
https://www.cnblogs.com/Leo_wl/p/10400983.html
更加详细可以看看《Rx.NET In Action》这本书。