ESFramework介绍之(26)-- 支持复杂插件(InnerDealer 和 InnerDispatcher)

    (本文内容适合于 ESFramework V0.2+)
    通常,最单纯的情况是一个插件对应某一特定类型的功能请求,但是,在有的应用中也会出现这样的情况,有多种类型的功能请求相互关联、并且可能交叉,如果是这样,对应每种类型的请求都开发一个插件可能会非常困难,因为这可能会牵涉到插件之间的相互引用/访问,这违背了插件的“自治”性。最好的办法还是将它们放在一个插件中,通过ServiceItemIndex(你一定还记得消息头定义中除了ServiceKey外还有个ServiceItemIndex属性)来区分相互关联的各种请求类型。
    当涉及的请求类型非常多时,我们的插件会变得非常复杂,通常的解决方案是在插件内部构建“内部处理器”InnerDealer,然后将ServiceItemIndex映射到对应的“内部处理器”上,这个映射可以由“内部分派器”InnerDispatcher完成。需要注意的是,并不需要为每个ServiceItemIndex都构建一个“内部处理器”,一个“内部处理器”可能能处理多个ServiceItemIndex的请求类型。下面我们重点关注“内部处理器”和“内部分派器”的实现。
   
    内部分配器接口IInnerDispatcher定义如下:
    public interface IInnerDispatcher
    {        
        
string AddinAssemblyName{set ;} //本插件程序集的名称

        
void Initialize() ;
        IInnerDealer GetDealer(
int serviceIndex) ;
    }

    最主要是GetDealer()方法的实现,它根据消息头中的ServiceItemIndex返回对应的内部处理器,你也许想到了,这可以通过Switch分支将serviceItemIndex映射到对应的内部处理器,然后这种集中管理的方式不是很方便,比如,当增加/删除一个内部处理器时,就要在这里增加/删除对应的分支语句。更好的办法是,让内部处理器能自己暴露它能处理的ServiceItemIndex的集合,这样,在运行时,可以通过反射动态的构建Mapping表,从而就避开了Switch语句及其引入的繁琐。
    内部处理器接口定义如下,它通过ServiceIndexCollection属性暴露了它能处理的ServiceItemIndex集合。
    public interface IInnerDealer
    {
        
int[] ServiceIndexCollection{get ;}

        NetMessage DealRequest(NetMessage reqMsg) ;
    }
    
    现在,我们可以实现IInnerDispatcher的Initialize方法来动态构建Mapping表了:
        private void Initialize()
        {
            Assembly[] asses 
= AppDomain.CurrentDomain.GetAssemblies();
            Type supType 
= typeof(IInnerDealer)  ;

            
foreach (Assembly ass in asses)
            {
                
string[] names = ass.FullName.Split(',') ;
                
if(names[0].Trim() == this.addinAssemblyName)
                {
                    
foreach(Type t in ass.GetTypes())
                    {
                        
if(supType.IsAssignableFrom(t) && (!t.IsAbstract) && (! t.IsInterface) )
                        {
                            IInnerDealer dealer 
= (IInnerDealer)Activator.CreateInstance(t) ;
                            
if(dealer.ServiceIndexCollection != null)
                            {
                                
foreach(int serKey in dealer.ServiceIndexCollection)
                                {
                                    
this.htDealer.Add(serKey ,dealer) ;
                                }
                            }
                        }
                    }

                    
break ;
                }
            }
        }

    可以在IAddin.OnLoading方法中调用InnerDispatcher的Initialize方法进行初始化。

    IInnerDispatcher的GetDealer方法就显而易见了:
        public IInnerDealer GetDealer(int serviceIndex)
        {
            
return (IInnerDealer)this.htDealer[serviceIndex] ;
        }

    功能插件的DealRequestMessage就变得相当简单:
        public ESFramework.Network.NetMessage DealRequestMessage(ESFramework.Network.NetMessage reqMsg)
        {        
            IInnerDealer dealer 
= this.dispatcher.GetDealer(reqMsg.Header.ServiceItemIndex) ;
            
if(dealer == null)
            {
                
return null ;
            }

            
return dealer.DealRequest(reqMsg) ;
        }
    
    插件中接下来需要做的工作就是实现你需要的IInnerDealer,实现的内部处理器不需要进行注册,它会在初始化插件时动态创建并被加入到Mapping表。需要注意的是,内部处理器的实现必须有一个无参的构造函数,否则,反射创建处理器实例将会抛出异常。
   

上一篇文章:ESFramework介绍之(25)-- 在插件中使用NHibernate

转到  :ESFramework 可复用的通信框架(序) 
posted @ 2006-04-25 19:54  zhuweisky  阅读(2332)  评论(4编辑  收藏  举报