现在的位置: 首页 > 综合 > 正文

分享CommunityServer(3) –Provider

2013年08月15日 ⁄ 综合 ⁄ 共 5545字 ⁄ 字号 评论关闭

Provider实现 

Provider 是重配置轻编程的第二个体现。
我们都知道分层设计很重要,也知道在保持结构稳定的基础上,应当做到最大的灵活性,所谓具体环境的无关性。比如我们设计的时候可以通过分析,将一些功能进行抽象,并独立出来。比如,我们需要做到数据库无关,我们需要将全部数据访问设计到数据库部分进行独立设计,并通过分析提炼出相应的功能抽象,然后可以根据实际的数据库,设计相应的面向特定数据库的数据访问类,以便做到最终可以灵活通过配置文件,来切换不同的数据驱动。
Provider 的定义在 CSConfiguration.cs,该类只是一个存储Provider的实体类,用来描述具体的功能的Provider,从XMNode中分析出数据,主要有 Name(Provider的名称)、 ExtensionType(扩展类型)、Type(类型字符串),另外,还适应更多的设定,Provider还增加一个名Attributes的值对收集,通过键名可获取值。
CS中的Provider都是采用静态Instance方法来获取的,在名为instance的静态函数中进行从字符串到一个类实例的,这一切当然是得益于.net的反射功能。具体我们从一个实例来分析:
 
分析 CommonDataProvider.cs
。。。。。。
     #region Instance
        private static CommonDataProvider _defaultInstance = null;
        static CommonDataProvider()
        {
            CreateDefaultCommonProvider();//静态构造函数在第一次调用该类的任何静态方法前进行构造
        }
         ……
        private static void CreateDefaultCommonProvider()
        {  
            CSConfiguration config = CSConfiguration.GetConfig();//获得全局配置类,这个上一篇进行了分析           
            Provider sqlForumsProvider = (Provider) config.Providers[CommonDataProviderName];
//从provider集合中获取名为 “CommonDataProvider 的(CommonDataProviderName是private string类型的数据成员)provider ,注意 sqlForumsProvider 的类型是一个描述逻辑组件的实体信息类,并不是真正的提供功能的类。就好像产品说明书只是 描述产品的,而不是产品。这里的provider具体实例就是一个产品说明书,而下 _defaultInstance 才是真正的提供功能的产品
            _defaultInstance = DataProviders.CreateInstance(sqlForumsProvider) as CommonDataProvider; //通过读取provider(产品说明书)信息后进行反射 活动 来创建功能的实际实例。
        }       
        #endregion
。。。。。。
我们需要注意了 , CommonDataProvider 在此是一个抽象类 (public abstract class CommonDataProvider),必须通过具体的抽象,对于Data类型的provider,CS通过一个 sealed 类 DataProviders 来实现实例化 CreateInstance 细节如下:
     public static object CreateInstance(Provider dataProvider)
        {             
            string connectionString = null; //dataProvider.Attributes["connectionString"];
            string databaseOwner = null;// dataProvider.Attributes["databaseOwner"];
            GetDataStoreParameters(dataProvider, out connectionString, out databaseOwner);
            //Get the type
            Type type = Type.GetType(dataProvider.Type);     //通过反射获得类实例的Type
            object newObject = null;
            if(type != null)         //存在 Type
            {
                newObject = Activator.CreateInstance(type,new object[]{databaseOwner,connectionString}); //反射获取实例
            }           
            if(newObject == null) //If we can not create an instance, throw an exception
                ProviderException(dataProvider.Name);
 
            return newObject;
        }
基本上,Provider模式利用.net反射功能,实现通过.congfi中的xml节点描述就创建最终的实例,就是利用了反射的能力。对于其他provider配置节点中的组件 ,都是类似这类方法实现的。DataProviders有点 “将provider描述变成具体的功能组件实例”的工具。
通常,都在 CommunityServerComponents 工程中将需要的可以利用provider模式进行设定的功能,利用abstract 类进行描述功能,然后在其他工程(如数据访问provider单独成为一个工程)中实现这个抽象类的具体实例,但是会继承这类的instance能力。
全部Provider的功能设计在 CommunityServerComponents 的 Provider 目录,
 
ApplicationKeyProvider           提供将Url查询串等转换为应用程序键 ApplicationKey 的功能,如果需要改变ApplicationKey的映射规则,可覆盖改类,修改comuunityserv.config即可实现。
 
ChineseTokenizeProvider        提供中文分词的接口,其中的搜索需要进行分词,而分词有不少独立算法,可以通过Provider设定来置换专用算法。改类是一个抽象类,你要实现的方法其实仅有一个 public abstract string[] ChineseTokenize(string input); 也就是将输入字符串,通过分词算法返回字符串词数组
 
CommonDataProvider 上面基本上已经提供了分析,该类相当庞大,并且按照数据库表实体表大致进行了分组,基本上全部数据库对象操作都可以在此进行定义。通过继承该类可以实现具体的面向不同数据库的版本。如过实现了面向Access的版本,就应该从此类继承实现,并修改communityServer.config的相关provider配置节
 
EmailQueueProvider  提供对于Email队列操作的定义,分别有 QueueEmail DequeueEmail DeleteQueuedEmail 等操作需要覆盖实现。
 
EmailTemplateProvider 提供邮件模板处理功能的provider基类,主要定义的模板操作有GetTemplate,并提供基础的对于Email模板的功能,方便后类实现。GetTemplate就是要求将发送的email通过专用模板,进行模板操作后获得特定的邮件正文。
 
ExtensionModule 定义了对于CS的插件模板的定义,通过provider模式进行替换,比如,你要一个CMS模块,你只需要实现特定的方法 Init 和 ProcessRequest 方法就可实现插件替换。
 
SearchProvider 提供了对于系统内搜索的可替换功能的定义。
 
UrlReWriteProvider          提供对于Url重写的功能实现,后将专题介绍。
 
 
如果我们有需要对某个特定功能进行灵活性处理,该如何做?我们就针对分词provider进行分析吧。
 
首先,我们需要创建抽象类,定义provider的基本功能需求,如ChineseTokenizer.cs中定义了分词的功能,输入字符串,返回词组 public abstract string[] ChineseTokenize(string input);
然后,我们集成该类,实现其抽象类功能。具体,我们可以添加一个simpleChineseTOkenizer
public class ChineseTokenizer :ChineseTokenizeProvider
     {
         public ChineseTokenizer()
         {}
     #region ChineseTokenizeProvider 成员
              public override string[] ChineseTokenize(string input)
              {
                   try
                   {
                        someWordSeg.WordSeg dictSeg=new WordSeg();
                       return dictSeg.Segment(input);  //分词
                   }
                   catch(Exception )
                   {//出现例外
                   }
                   return input.Split("".ToCharArray());
              }
     #endregion
someWordSeg是一个分词的组件,实现中文分词。ChineseTokenizeProvider 的分词实际由此组件实际提供。
 
实现了具体的provider功能后(把具体的实现类放置在SearchBarrel工程中),我们需要登记provider,具体在communityserver.config中添加一个节点,我们取名为
 
                   <add
                    name=      "ChineseTokenizeProvider"
                    type="CommunityServer.Components.SearchBarrel. ChineseTokenizeProvider, CommunityServer.Components.SearchBarrel"/>
CommunityServer.Components.SearchBarrel. ChineseTokenizeProvider 是类名,CommunityServer.Components.SearchBarrel是程序集名。
 
这样,全局就可以知道存在这样一个分词组件,但是无需知道具体的实现,然后我们在需要分词功能的时候进行如下的步骤获取分词功能:
.
string[]  words = ChineseTokenizeProvider.Instance().ChineseTokenize(searchTerms);
instance 最终是按照如下逻辑进行实例化provider的:
。。。
CSConfiguration config = CSConfiguration.GetConfig();
         Provider chineseProviders = (Provider)config.Providers["ChineseTokenizeProvider"];
          _defaultInstance = Activator.CreateInstance(Type.GetType(chineseProviders.Type)) as ChineseTokenizeProvider;
。。。
简单总结就是:
1、 抽象出可按照provider设计的功能需求,设立一个抽象类,并在抽象基类定义instance函数,能够通过instance函数获得某个具体的provider实例,这就是做到所谓契约编程了。契约编程,不一定就要通过接口来实现。
2、 然后实现一个具体的实现类,实现具体的功能
3、 登记provider项目,在communityserver。Config中
4、 在需要provider的地方通过抽象类的instance方法实现具体组件的实例化,达到了组件化、定制化的组件协作。这样的设计会合理划分类边界,灵活性和实用性结合。也就是体现“重配置、轻编程”

 

抱歉!评论已关闭.