UniRx---简单封装一个SubjectManager 解耦主题和监听者

Subject<T> 是UniRx 推荐的 事件实现方式 UniRx是AssetStore上的一款免费插件,但其实他的出身很地道,脱胎于微软的Rx框架,主要思想是像Linq那样对订阅的事件进行操作,并且他还能对操作进行 时间调度,线程调度,而UniRx就是Rx的Unity版) 。在开发中,这种数据发射工作在使用UniRx时,可以把事件触发时调用观察者回调并传递参数的行为 形象的理解成发射,这样有助于理解万物皆Stream的这种编程思想,一般会让订阅方和发射方解耦,彼此不用了解对方的存在,SubjectManager的意义就在于此。 此系统中,用继承于SubjectArgs基类的一个一个子类来表示不同的事件,同时类本身作为事件传递的参数类型,你可以在里面随便定义任何你需要在这种事件里传递的数据

下面是实现

//主题参数基类
public abstract class SubjectArgs
{
    public object sender = null;
    public abstract int SubjectId { get; }
}
//主题管理器
public class Subject_Manager  {
  //主题字典,以主题传递的参数类型提供的hashCode为key
    private Dictionary<int, Subject<SubjectArgs>> mSubjectDic = new Dictionary<int, Subject<SubjectArgs>>();
//通过id拿到主题  
  public IObservable<T> GetSubject<T>()where T : SubjectArgs
    {
        int subjectId = typeof(T).GetHashCode();
        Subject<SubjectArgs> subject = null;      
        if (!mSubjectDic.TryGetValue(subjectId, out subject))
        {
            subject = new Subject<SubjectArgs>();
            mSubjectDic.Add(subjectId, subject);
          
        }
        return subject.Select(_ => _ as T);
    }
   //数据,发射!
    public void Fire<T>(T e)where T:SubjectArgs
    {
        Subject<SubjectArgs> subject = null;
        if (!mSubjectDic.TryGetValue(e.SubjectId, out subject))
            return;

        subject.OnNext(e);
    }
	
}

加一层静态封装,用起来稍微舒服点

public static class SubjectManager
{
   private static Subject_Manager mInstance = new Subject_Manager();
    public static IObservable<T> GetSubject<T>() where T : SubjectArgs
    {
        return mInstance.GetSubject<T>();
    }
    public static void Fire<T>(T e) where T : SubjectArgs
    {
        mInstance.Fire<T>(e);
    }
}

然后进行测试  


public class HappySubjectArgs : SubjectArgs //Todo用对象池缓存这些炮弹...
{
    public static readonly int ID = typeof(HappySubjectArgs).GetHashCode();
    public override int SubjectId { get { return ID; } }
    public int HappyDegree = 0;
}

public class SMTest : MonoBehaviour {
 //注销器集合,所有订阅的注销器都往这里塞
    CompositeDisposable mSubjectUnRegister=new CompositeDisposable();
    void Start () {
        //只接收开心程度大于10的发射...
        SubjectManager.GetSubject<HappySubjectArgs>().Where(e => e.HappyDegree > 10)
            .Subscribe(e => print("开心程度:"+e.HappyDegree+"...看起来很开心")).AddTo(mSubjectUnRegister);
        //开心程度会随着点击增长...
        Observable.EveryUpdate().Where(_ => Input.GetMouseButtonDown(0))
            .Select((_,count)=>count)
            .Subscribe(count => SubjectManager.Fire(new HappySubjectArgs() { HappyDegree = count}));
        //没有多余字段的类...看起来真的很舒爽...
    }
void OnDestroy()
    {
        //此对象销毁时注销器注销 就算重复注销也没关系 这就是UniRx用起来舒服的点点滴滴...
        mSubjectUnRegister.Dispose();
    }
}

这样你可以在任何地方发射 在任何地方订阅

同时可以考虑增加一种轻量级的消息发射方式,使用string作为消息的key,object作为传递的参数(value是subject<object>)

这样不用每种消息都要去实现一个类,但是缺点是如果参数是struct的话,就要装箱和拆箱

总之,UniRx版的事件subject 的优点主要在于 可以对发射来的数据进行各种定制操作, 无缝对接UniRx所有的操作符,不多,也就七八十个把(滑稽脸),随便举个例子好把,比如First,只要在订阅前添加这个操作符就能优雅的实现只订阅一次的功能

猜你喜欢

转载自blog.csdn.net/zwlstc/article/details/84957395