一直在寻找.NET下优秀的Scheduler项目,找来找去似乎就只有一个从Java移植过来的Quartz.NET,以下简称QN, 网上也有不少人在写入门教程,更不乏盛赞者,我很早就下了它的源代码一直没时间看,最近闲暇,又去下了最新的版本打开翻翻,真是大跌眼镜,不知道是不是我水平太次的缘故,我实在觉得QN的代码不论结构还是编程风格都难登大雅之堂,阅读时候总感觉代码晦涩到极点,比起微软开源的Enterprise Library之类的代码实在相去甚远。我刚开始读了几段就不想看了,于是到网上看看有没有人分析他的源码,找到几篇所谓的源码结构分析都是入门教程,英文的也大多是配置教程。于是又了下面这堆牢骚话。

      也希望看到我文章的高手不吝赐教,下面我来戳戳QN代码的几宗罪(补充,我下到的源码是1.0的):

      1。接口泛滥,但缺乏层次:

       举几个例子:

       无聊接口:ISchedulerFactory, 这样的接口我实在看不出有什么作用,难道是隐喻使用者在代码中使用QN尽量用抽象工厂模式?OK,这个也勉强可以理解,但是我们看看实现类StdSchedulerFactory, 用抽象工厂吧,public的构造函数原型是public StdSchedulerFactory(NameValueCollection props),要抽象工厂配置复杂度可想而知了,更让我昏迷的是StdSchedulerFactory又有个静态属性DefaultScheduler,似乎就是静态方法Create的意思,那就是简单的帮助类嘛,代码语义实在混乱。看看另一个实现类 DirectSchedulerFactory , 第一行就是private static readonly DirectSchedulerFactory instance = new DirectSchedulerFactory(); 单例模式?我吐血~连代码的始作俑者对于同一接口的实现理念都是各不相同的,那使用者更是迷糊了,ISchedulerFactory 层次的抽象变得没有任何意义。

      孤岛接口:IRemotableQuartzScheduler,  仔细看看IScheduler接口, 字面语义应该是IRemotableQuartzScheduler : IScheduler,看看代码,IRemotableQuartzScheduler 接口和IScheduler几乎一样,就是方法中多了Context参数,我耐心的读了一下,就是因为使用了JobStore后instanceId改变而无法实现IScheduler才搞出了一个IRemotableQuartzScheduler ,然而事实上IRemotableQuartzScheduler 实现类QuartzScheduler 完全具备了实现IScheduler的功能,等等...听起来像什么?聪明的你嗅到适配器模式的味道了吧, 聪明,作者确实在StdScheduler使用了“适配器模式”,可是实现的也有些牵强,instanceId居然又是在外部初始化的,我再吐血~ 别急,还有,代码几乎都是用QuartzScheduler,而没有用接口IRemotableQuartzScheduler,这种孤岛式的接口根本没有为我们提供插件功能,留他作甚~。

      残缺的接口:IJobStore, 这个接口是用来驻留JOB信息的,本来大家都会以为实现了IJobStore就能驻留JOB信息了,然而看看StdSchedulerFactory代码您会离奇的发现,数据库存储模式必须要从JobStoreSupport继承,虽说JobStoreSupport也实现了IJobStore,但是StdSchedulerFactory代码中有这个一段判断if(js is JobStoreSupport),这个说明什么问题?IJobStore的信息不够,这种代码直接打乱了内部的一致性,我们不可能去继续的加入if(js is MyJobStore),我认为深层的抽象出IJobStoreSupport是更好的做法,这样我们不必使用JobStoreSupport也能享受DbProvider的配置。

      好了,这个是接口问题,我们来看看编程风格问题:

      互调用频繁:在看代码的过程中我发现QN的代码中经常出现A.M(B), B.N(A)这种问题,而这种代码仅仅是为了赋值一个属性A.B和B.A,我实在搞不懂这种设计如何产生的,我认为使用一个ABManager协调AB调用然后new ABManager(A,B)来保持AB的独立性不是更好?

      方法代码超级长:开篇一看StdSchedulerFactory的Instantiate方法居然有700行,多的不说,把从配置文件里获取属性然后赋值到对象这一操作重构一下至少可以少写1/3的代码,在佩服作者体力非凡的同时我不禁对QN代码的健壮性表示深深怀疑.

      无聊的虚方法: 看代码的您如果仔细点会发现,N多类的实例方法基本都是虚方法,但您随便拿出一个虚方法让你自己实现你会觉得无从下手,甚至连重载的几个方法都全是虚方法,崩溃吧。似乎代码里的虚方法几乎是不加思索的写的,根本不是出于提供给使用者灵活性。

      项目文件和命名空间之乱:项目文件并没有统一组织,你会猜想是否SPI文件夹表示SimpleInterface,但你又会发现有TriggerFiredBundle这个捣蛋鬼,当您在Impl目录找到StdScheduler后你会发现他的接口在根目录,总是太多的意外和惊喜被偷偷藏在了其他地方。

      再看看第三方插件的问题:

      Log4Net之痛:我们意外的发现一个代码中到处使用的ILog接口居然来自于一个第三方代码,对于不想用Log4Net的人来说我们还必须拖着那个沉沉的Common.Log.dll,我一直认为关键接口应该是自己定义的,我们不应该让自己的接口受第三方代码的影响(当然发誓不更换第三方类库版本的我不勉强你)。最后我们看看ILog,仔细看代码你会发现Enable那几个属性根本没用,代码中很多地方根本没有管那几个属性。

 

      总结,QN是一个号称企业级的Scheduler类库,但其代码质量是否达到外界吹嘘的企业级,确实值得商榷,然而我们也可以看到QN也确实不乏出彩之处,例如JobDataMap的灵活,Trigger与Job分离等设计思路确实值得借鉴,若不在代码重构方面下功夫,作为开源项目是不会像EnterpriseLibrary深入人心的。希望未来的QN能够越来越好,毕竟.NET下的Scheduler并不常见。

    

      PS:谁发现优秀的.NET平台下的开源Scheduler框架麻烦告诉我。

posted on 2009-04-20 21:39  sharping  阅读(4621)  评论(10编辑  收藏  举报