好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

插件框架实现

插件框架实现

一步步实现自己的框架系列:插件框架实现

 不好意思各位同学,本系列文章更新比较慢,因为我也要工作,况且还需要抽出时间编码验证理论,当然找借口总归是不好的,我们都是人,需要休息与娱乐嘛。

  其实.net平台已经有自己的插件框架,比如MEF,MAF这些都是.net自带的框架,前者注重灵活,后者注重物理隔离。不过这不是今天的重点,今天的重点是做我们自己的框架。

  第一步:插件模型设计

  既然是插件框架就会有插件,就会有放插件的地方,我们就需要设计插件容器,这样既可以灵活的管理插件,也使代码的层次结构更加清晰,图示紫色部分是插件与插件容器部分,外边蓝色的就是我们需要使用插件的拥有者,我发现一张图片的效果远比一堆庸俗的文字效果来的更直接,所以如果能用图表达的地方我尽量用图去表达。

  第二步:接口设计

    既然是插件我们如何标识我们的插件呢,看看MEF的导出设计,

[Export]

public class Part

{

}

这里我们借来用下,没错,就是使用特性来标识我们导出的插件,既然这种设计这么优秀我们为什么不用呢?

单部件特性设计

 namespace   GL.Core
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple  =  false , Inherited =  false  )]
      public   class   SinglePartAttribute : Attribute
    {

    }
} 

多部件特性设计

 namespace   GL.Core
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple  =  false , Inherited =  false  )]
      public   class   MultiplePartAttribute : Attribute
    {

    }
} 

  为什么会设计两个特性呢?我们在使用一些功能时,比如设备管理,同一个客户端实例只需要一个设备管理的插件就够了,尽管我们可以写很多,但同一时刻我们只需要一个实例去管理就可以了,那多部件呢,比如我们客户端是一个图片效果处理程序,同一时刻,我们既可以使用图片灰度功能,也可以使用图片锐化功能,也可以使用负片功能等等,那么这种设计是合理的。
  既然是插件,那么插件的描述信息必不可少,那么怎么设计我们的插件描述信息呢——特性,这里也使用特性,

比如这样定义我们的插件,我们既可以知道这是一个插件,又能获取插件的描述信息,简洁明了。

 [Single]
[PartMetadata(  "  Name  " , "  PartManage  "  )]
[PartMetadata(  "  Author  " , "  GL  "  )]
  public   class   PartManage
{

} 

插件元数据描述

 namespace   GL.Core
{
      public   class   PartMetadata : Attribute
    {
          public   string  Name {  get ;  private   set  ; }

          public   object  Value {  get ;  private   set  ; }

          public  PartMetadata( string  name,  object   value)
        {
              this .Name =  name;
              this .Value =  value;
        }
    }
} 

  为了方便在内存中操作我们的插件,为插件设计一个信息描述实体是必须的,当然,根据实际需要大家可以自己添加或删除一些描述信息,为方便扩展插件描述这里给出了描述的接口。

 namespace   GL.Core
{
      public   interface   IPartInformation
{ /// <summary> /// 插件名称 /// </summary> string PartName { get ; } /// <summary> /// 插件版本 /// </summary> string PartVersion { get ; } /// <summary> /// 插件描述 /// </summary> [DefaultValue( "" )] string PartDescription { get ; } /// <summary> /// 插件类型 /// </summary> Type PartType { get ; } /// <summary> /// 依赖的插件类型 /// </summary> [DefaultValue( null )] Type[] PartDependencies { get ; } /// <summary> /// 插件作者 /// </summary> [DefaultValue( "" )] string PartAuthor { get ; } /// <summary> /// 最后修改日期 /// </summary> [DefaultValue( "" )] string LastModifiedDate { get ; } /// <summary> /// 备注 /// </summary> [DefaultValue( "" )] string Comment { get ; } } }

  有时候某些插件我们不希望启用,或者多插件版本切换的时候,我又不想每次都替换那些Dll,毕竟那是些麻烦又无聊的事情,这时候我就的给我们的每一个插件添加一个配置项信息了,想启用什么或者禁用什么改改配置文件就好了(当然,这工作交给小弟就好了,或者弄个配置文件修改的工具,随便一个人就能切换了)。
没想到还能为插件配置什么,就一个是否启用

 namespace   GL.Core
{
      public   class   IPartConfigration
    {
          public   string  PartType {  get ;  set  ; }
          public   bool  IsEnable {  get ;  set  ; }

          public   IPartConfigration() { }
        
          public  IPartConfigration( string  partType,  bool   isEnable)
        {
              this .PartType =  partType;
              this .IsEnable =  isEnable;
        }
    }
} 

  跟插件相关的就差不多了,下面来设计下我们的插件容器吧,所谓容器就是能放东西的东西,我感觉上句话包括这句其实是废话,呵呵。既然是插件容器就得能放插件,没有接口设计的类,让人理解起来总是那么费劲,首先来看下我们插件容器接口的设计:

 namespace   GL.Core
{
      public   interface   IGLPartContainer
    {
          ///   <summary> 
         ///   单实例插件
          ///   </summary> 
         IList <Type> SingleParts {  get  ; }

          ///   <summary> 
         ///   多实例插件
          ///   </summary> 
         IList <Type> MultipleParts {  get  ; }

          ///   <summary> 
         ///   获取所有插件实例与配置信息
          ///   </summary> 
        IDictionary< object , IPartInformation> ActivePart {  get  ; }

          ///   <summary> 
         ///   添加插件
          ///   </summary> 
         ///   <param name="partType"></param> 
         ///   <param name="partConfigration"></param> 
         void   AddPart(Type partType, IPartConfigration partConfigration);

          ///   <summary> 
         ///   移除指定实例插件
          ///   </summary> 
         ///   <param name="partInstance"></param> 
         void  RemovePart( object   partInstance);

          ///   <summary> 
         ///   获取单实例插件
          ///   </summary> 
         ///   <param name="partType"></param> 
         ///   <returns></returns> 
         object   GetSinglePart(Type partType);

          ///   <summary> 
         ///   获取多实例插件
          ///   </summary> 
         ///   <param name="partType"></param> 
         ///   <returns></returns> 
        IEnumerable< object >  GetMultipleParts(Type partType);

          ///   <summary> 
         ///   获取插件信息
          ///   </summary> 
         ///   <param name="partType"></param> 
         ///   <returns></returns> 
        IPartInformation GetPartInformation( object   instance);

          ///   <summary> 
         ///   获取指定类型插件是否启用
          ///   </summary> 
         ///   <param name="partType"></param> 
         ///   <returns></returns> 
         bool   IsPartEnabled(Type partType);

    }
} 

第三步:类的实现

  接着就是类的实现,里面会涉及到反射的应用,linq等基本应用

  View Code

第四步:单元测试

  好了,我们插件存放的容器就设计好了,来个单元测试,接下来享受下我们的成果吧:

  class   Program
    {
          static   void  Main( string  [] args)
        {
            Program p  =  new   Program();
              var  configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "  PartConfig.config  "  ) ;
            IGLPartContainer cont  =  new  GLPartContainer<Program>(p, configPath,  new   string  [] { AppDomain.CurrentDomain.BaseDirectory });
              var  p1 = cont.GetSinglePart( typeof  (Part1));

            Console.WriteLine(  "  Part1 Full Name : {0}  "  ,p1.GetType().FullName);

              var  xxx =  cont.GetPartInformation(p1);

            Console.WriteLine(  "  Part1 Metadata : {0}  "  , xxx.PartName, xxx.PartType);

              var  p2 = cont.GetMultipleParts( typeof  (Part2));

            Console.WriteLine(  "  Part12 Full Name : {0}  "  , p1.GetType().FullName);

            Console.ReadLine();
        }
    } 

 运行结果:

既然来了,何不留下您的脚印,如果您觉得本文对你有所帮助的话,请点击推荐,如果你想关注本系列文章的话,请点击关注我。

 

 

分类:  C#

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于插件框架实现的详细内容...

  阅读:40次