设计
在使用.NET技术开发应用程序框架的时候,我们通常会设计一种配置数据结构,在代码中使用继承于ConfigurationSection、ConfigurationElement以及ConfigurationElementCollection的类来表示这样的数据结构,之后,在应用程序的配置文件中,就可以很方便地使用与之相对应的XML标记(Tags)来表示配置数据了。这些内容对于一个资深的.NET开发人员来说,应该是非常熟悉的。可以说,.NET中的配置文件是一种最基本最常见的配置数据提供方案,于是,当我们希望为应用程序框架提供多样化的配置方式时,这种基于配置文件的方式就成为了其中一种必不可少的选择。除此之外,我们还可以根据框架本身的特性,提供诸如基于其它XML文件、基于数据库或者直接代码编写的配置方式。
为了能让框架同时支持配置文件以及其它的配置方式,在设计上就需要将这些不同的配置方式统一起来。上面也分析过,配置文件的方式是必不可少的,因此,我们可以让这些方式对框架透明,而使得框架仅感知到当前只有配置文件这样一种方式。换句话说,在框架的实现过程中,当需要用到配置数据时,框架代码仅会使用到那些继承于ConfigurationSection、ConfigurationElement以及ConfigurationElementCollection的类型。
首先,定义一个配置源(Configuration Source)接口,该配置源接口会对配置节(Configuration Section)进行封装,由于配置节包含了对其它配置元素(Configuration Element)和配置元素集(Configuration Element Collection)的引用,因此,配置节实际上是整个配置信息聚合的聚合根。然后,针对不同的配置方式,创建实现配置源接口的类,并在这些类中以不同的方式初始化配置节对象,比如可以通过System.Configuration.ConfigurationManager来读取配置文件中的配置节,或者通过访问数据库来获得配置数据等。最后,框架仅需以依赖注入等方式获得配置源的具体实现,即可获得配置数据。下面的类图展示了这种设计的参与者及其之间的关系,为了简化描述,该类图仅包含了基于配置文件和基于源代码编写的两种配置实现方式。

上图中的IConfigurationSource接口就是配置源接口,ConfigFileConfigurationSource和RegularConfigurationSource是实现了该接口的两个类,ConfigFileConfigurationSource类通过使用标准的.NET配置系统以从配置文件中读入配置节;而RegularConfigurationSource则向调用方提供了SetElement、AddElement等公有方法,以便开发人员可以直接在代码中调用这些方法来向框架提供配置数据。应用程序框架的Application类会在构造函数中接收IConfigurationSource的具体实现以便初始化其ConfigSource属性。ApplicationFactory类是一个单例类(Singleton),它的CreateApplication静态方法同样接收IConfigurationSource的具体实现以便创建Application实例,与此同时,ApplicationFactory会向外公开CurrentApplication属性,以便在框架的任何地方都能够获得当前运行的Application实例,进而获得定义在Application实例中的配置源。
采用这种设计,要为框架提供新的配置方式就变得轻而易举了。例如,假设我们希望框架还能够从数据库读取配置数据,那么我们只需要创建一个DatabaseConfigurationSource的类,使其实现IConfigurationSource接口,而在这个类中,通过访问数据库来设置Config属性即可。