[CLK Framework] CLK.Settings

CLK.Settings是一个跨平台的参数存取模块。在开发跨平台功能模块时,使用CLK.Settings能够帮助开发人员,简化参数存取功能的开发工作。


[CLK Framework] CLK.Settings - 跨平台的参数存取模块

问题情景

开发功能模块的时候,常常免不了有一些参数(例如ConnectionString),需要存放在Config档(App.Config、Web.Config)。而.NET Framework也很贴心的提供System.Configuration命名空间里的类,用来帮助开发人员简化存取Config档的开发工作。但是当功能模块的开发,是以跨平台执行为目标来做设计的时候,因为不是每个平台都允许Config档的存在,所以连带的System.Configuration命名空间里的类,也并不支持跨平台的参考使用。

像是开启一个便携式类库项目(Portable Class Library),来设计横跨ASP.NET、Windows Phone两个平台的功能模块时,因为Windows Phone平台不支持Config档的存在,所以开发时无法在项目中加入System.Configuration命名空间的参考,用来存取Config档内的参数设定。

遇到这样跨平台的功能模块开发,该如何处理跨平台的参数存取呢?

解决方案

首先,不是每个平台都允许Config档的存在,每个平台各自拥有平台自己的参数存取功能,像是Windows Phone平台不允许的Config档的存在,但是可以透过操作IsolatedStorage来提供参数存取功能。为了切割与这些平台参数存取功能的相依性,可以套用IoC模式在功能模块上,用以建立一层参数存取界面,让跨平台功能模块单纯相依于同模块内的参数存取界面。接着再套用Adapter模式建立转接对象,来将每个平台的参数存取功能,转接成为参数存取界面的实践。这样后续就可以依照执行平台的不同,为跨平台功能模块注入不同的参数存取界面实践,用以提供不同平台上参数存取的功能。

假设,开发一个跨平台功能模块,就要对应开发一个套用Adapter模式的转接对象,来将每个平台的参数存取功能转接成为参数存取界面的实践。这样的开发流程在遇到跨平台功能模块越来越多的情况下,会发现需要开发的转接对象数量会迅速膨胀,进而成为开发人员工作上的负担。

为了简化转接对象的开发工作,可以将参数存取功能抽象化之后,建立成为一个共用的参数存取模块,并且这个共用参数存取模块同样透过套用IoC模式,来切割与平台参数存取功能之间的相依性,让这个共用参数存取模块可以跨平台使用。后续只需要为每个平台专有的参数存取功能,开发一个转接进共用参数存取模块的转接对象,就能让每个使用共用参数存取模块的跨平台功能模块,能够透过平台的参数存取功能来存取参数设定。

模块设计

CLK.Settings是一个跨平台的参数存取模块。在开发跨平台功能模块时,使用CLK.Settings能够帮助开发人员,简化参数存取功能的开发工作。

模块下载

下载程序:由此进入GitHub后,点选右下角的“Download ZIP”按钮下载。

模块程序:CLK方案1 Domains数据夹CLK项目Settings数据夹

范例程序:CLK方案2 Samples数据夹1 CLK.Settings.Samples数据夹

(开启程序的时候,建议使用Visual Studio所提供的“大纲->折叠至定义”功能来折叠程序,以能得到较适合阅读的排版模式。)

对象结构

  • SettingContext

    • CLK.Settings模块的根节点对象。

    • 提供Locator功能(选用)。

  • SettingDictionary

    • 将ISettingRepository界面所提供的CRUD功能,转接为简单使用的Dictionary对象模式提供开发人员使用。

    • 继承自CLK.Collections.StoreDictionary

  • ISettingRepository

    • 套用IoC模式产生的边界界面。

    • 用来隔离系统与不同平台参数存取功能之间的相依性。

    • 提供参数数据进出模块边界的CRUD功能。

    • 继承自CLK.Collections.IStoreProvider

  • ConfigConnectionStringRepository

    • 继承ISettingRepository界面。

    • 转接Config档的连线字符串存取功能,用以提供系统来存取Config档中的连线字符串设定。

  • ConfigAppSettingRepository

    • 继承ISettingRepository界面。

    • 转接Config档的AppSetting存取功能,用以提供系统来存取Config档中的AppSetting设定。

  • MemorySettingRepository

    • 继承ISettingRepository界面。

    • 在内存中建立一个参数集合对象来存放参数设定,用以提供系统来存取内存中的参数设定。

对象交互

  • 读取参数

  • 枚举参数

  • 新增参数

  • 移除参数

使用范例

CLK.Settings.Samples.No001 - 建立模块

在使用SettingContext对象之前,必须先取得系统所使用的SettingContext对象,在范例中统一透过生成函数来提供SettingContext对象。例如下列范例中的生成函数,会建立一个SettingContext对象的子类:ConfigSettingContext对象,这个ConfigSettingContext对象会转接Config档的参数存取功能,用以提供系统来存取Config档中的参数设定。

  • 建立模块

    static SettingContext Create()
    {
        // SettingContext
        SettingContext settingContext = new ConfigSettingContext();
    
        // Return
        return settingContext;
    }
    

CLK.Settings.Samples.No002 - 读取参数

  • 配置文件

    
    
      
      
      
    
    
    
    
      
          
      
      
    
  • 读取参数

    static void Main(string[] args)
    {
        // Create
        SettingContext settingContext = Program.Create();
    
        // Get
        Console.WriteLine("nAppSettings");
        string argumentString = settingContext.AppSettings["Argument01"];
        Console.WriteLine(argumentString);
    
        Console.WriteLine("nConnectionStrings");
        string connectionString = settingContext.ConnectionStrings["Database01"];
        Console.WriteLine(connectionString);
    
        // End
        Console.WriteLine("nPress enter to end...");
        Console.ReadLine();
    }
    
  • 执行结果

CLK.Settings.Samples.No003 - 枚举参数

  • 配置文件

    
    
      
      
      
    
    
    
    
      
          
      
      
    
  • 枚举参数

    static void Main(string[] args)
    {
        // Create
        SettingContext settingContext = Program.Create();
    
        // List
        Console.WriteLine("nAppSettings");
        foreach (string key in settingContext.AppSettings.Keys)
        {
            string argumentString = settingContext.AppSettings[key];
            Console.WriteLine(argumentString);
        }     
    
        Console.WriteLine("nConnectionStrings");
        foreach (string key in settingContext.ConnectionStrings.Keys)
        {
            string connectionString = settingContext.ConnectionStrings[key];
            Console.WriteLine(connectionString);
        }                                   
    
        // End
        Console.WriteLine("nPress enter to end...");
        Console.ReadLine();
    }
    
  • 执行结果

CLK.Settings.Samples.No004 - 新增参数

  • 原始配置文件

    
    
      
      
      
    
    
    
    
      
          
      
      
    
  • 新增参数

    static void Main(string[] args)
    {
        // Create
        SettingContext settingContext = Program.Create();
    
        // Set           
        settingContext.AppSettings.Add("Argument04", "DDDDDDDDDDDDD");
    
        settingContext.ConnectionStrings.Add("Database03", "Data Source=192.168.3.3;Initial Catalog=DB03");
    
        // End
        Console.WriteLine("nPress enter to end...");
        Console.ReadLine();
    }
    
  • 结果配置文件

    
    
      
      
      
      
    
    
    
    
      
      
      
      
      
    

CLK.Settings.Samples.No005 - 移除参数

  • 原始配置文件

    
    
      
      
      
    
    
    
    
      
          
      
      
    
  • 移除参数

    static void Main(string[] args)
    {
        // Create
        SettingContext settingContext = Program.Create();
    
        // Set           
        settingContext.AppSettings.Remove("Argument03");
    
        settingContext.ConnectionStrings.Remove("Database02");
    
        // End
        Console.WriteLine("nPress enter to end...");
        Console.ReadLine();
    }
    
  • 结果配置文件

    
    
      
      
    
    
    
    
      
      
      
    

CLK.Settings.Samples.No006 - 更换来源

只要更换生成函数所提供的SettingContext对象,就可以更换系统所使用的参数设定来源。例如下列范例中的生成函数,改为会建立一个SettingContext对象的子类:MemorySettingContext对象,这个MemorySettingContext对象,会在内存中建立一个参数集合对象来存放参数设定,用以提供系统来存取内存中的参数设定。

(额外一提,作单元测试的时候,使用MemorySettingContext对象来取代ConfigSettingContext对象,就可以透过程序来提供测试用的参数设定,而不需要另外维护Config档来提供测试用的参数设定。)

  • 更换来源

    static SettingContext Create()
    {
        // AppSettingRepository
        MemorySettingRepository appSettingRepository = new MemorySettingRepository();
        appSettingRepository.Add("Argument05", "XXXXXXXXXXXXX");
        appSettingRepository.Add("Argument06", "YYYYYYYYYYYYY");
        appSettingRepository.Add("Argument07", "ZZZZZZZZZZZZZ");
    
        // ConnectionStringRepository
        MemorySettingRepository connectionStringRepository = new MemorySettingRepository();
        connectionStringRepository.Add("Database04", "Data Source=192.168.4.4;Initial Catalog=DB04;");
        connectionStringRepository.Add("Database05", "Data Source=192.168.5.5;Initial Catalog=DB05;");  
    
        // SettingContext
        SettingContext settingContext = new MemorySettingContext(appSettingRepository, connectionStringRepository);
    
        // Return
        return settingContext;
    }
    
  • 枚举参数

    static void Main(string[] args)
    {
        // Create
        SettingContext settingContext = Program.Create();
    
        // List
        Console.WriteLine("nAppSettings");
        foreach (string key in settingContext.AppSettings.Keys)
        {
            string argumentString = settingContext.AppSettings[key];
            Console.WriteLine(argumentString);
        }     
    
        Console.WriteLine("nConnectionStrings");
        foreach (string key in settingContext.ConnectionStrings.Keys)
        {
            string connectionString = settingContext.ConnectionStrings[key];
            Console.WriteLine(connectionString);
        }                                   
    
        // End
        Console.WriteLine("nPress enter to end...");
        Console.ReadLine();
    }
    
  • 执行结果


签名档
期许自己
能以更简洁的文字与程序,传达出程序设计背后的精神。
真正做到“以形写神”的境界。