如何从概念上处理程序中的大量配置参数?
How to handle large number of configuration parameters across a program conceptually?
想象一个软件系统,您有大约 100 个参数,每个参数都可以合理地更改(在我的例子中,这是一个机器学习研究系统)。显而易见的解决方案是将所有参数存储在一个配置文件中,这样系统易于处理和查看。
哪种方法更好:
- a) 在程序的入口点加载配置文件,并通过代码中的每个方法传递一大堆配置变量
- b) 在程序入口加载config文件,通过代码中的各个方法向下传递相关的config变量集合
- c) 在需要的地方直接加载配置变量
- d) 加载配置并使其成为全局
我愿意听取特定实施的建议或示例。目前我正在尝试嵌套配置变量,每个嵌套对象在代码中存储不同模块的配置。
我建议您执行以下步骤。
首先,使用支持多个 sections/scopes 概念的配置文件语法,最好是可嵌套范围。例如,XML 元素是我所说的可嵌套范围,而“.ini”文件提供不可嵌套的部分。 Java 属性文件不提供对范围的直接支持,但您可以通过使用语法 x.y.z
来表示范围 y
中的变量 z
来模拟此类支持,其中turn 嵌套在范围 x
中。 Config4*(我开发的)提供对嵌套作用域的直接支持。
其次,编写一个可配置的Foo
class的构造函数,如下伪代码所示:
Foo(Configuration cfg, String scope) {
_x = cfg.lookup(scope + ".x");
_y = cfg.lookup(scope + ".y");
_z = cfg.lookup(scope + ".z");
_bar = new Bar(cfg, scope + ".bar");
}
在上面的伪代码中,我使用 _
前缀来表示一个实例变量,我假设 Configuration
class 有一个 lookup()
操作需要范围名称,例如,cfg.lookup("foo.bar.abc")
将 return foo.bar
范围内的 abc
变量的值。
第三,你的应用程序的main()
函数可以写成如下伪代码所示:
main(...) {
String configFileName = ...; // obtain from command-line argument
String scope = ...; // obtain from command-line argument
Configuration cfg = parseConfigurationFile(configFileName);
Foo foo = new Foo(cfg, scope + ".foo");
... // create other configured objects
doRealWork(foo, ...);
}
最后,应用程序的命令行参数应指定:(1) 配置文件的名称,以及 (2) 包含 [=67] 配置变量的顶级范围(在配置文件中) =]宁应用程序。例如,假设 example.cfg
的结构如下:
instance1 {
foo {
x = "a value";
y = "another value";
z = "yet another value";
bar {
...
}
}
... # configuration for other objects
}
instance2 {
foo {
x = "...";
y = "...";
z = "...";
bar {
...
}
}
... # configuration for other objects
}
您可能 运行 您的应用程序 myApp.exe -cfg example.cfg -scope instance1
。
以上建议具有以下好处:
- 您的应用程序可以创建多个
Foo
对象,每个对象都可以进行不同的配置,只需将不同的 scope
参数传递给每个对象的构造函数即可。
- 用户可以根据需要灵活地在单个配置文件中存储多组配置变量。例如,用户可能有不同的配置变量集用于:(1) 不同的单元测试; (2)开发、UAT和生产环境; (3) 复制服务器应用程序的多个实例。
- 随着时间的推移,您可以编写一个遵循上述设计原则的可配置 classes 库。该可配置 classes 库可以在多个应用程序中重复使用。
我已经在我编写的几个基于 C++ 和 Java Config4* 的应用程序中使用了上述方法,它对我来说效果很好。如果您使用的语言内置了反射支持(例如 Java),那么另一种方法是使用依赖注入框架。如果您不知道那是什么,请在 Internet 上搜索 "dependency injection"、"inversion of control" 或 "Spring Framework".
想象一个软件系统,您有大约 100 个参数,每个参数都可以合理地更改(在我的例子中,这是一个机器学习研究系统)。显而易见的解决方案是将所有参数存储在一个配置文件中,这样系统易于处理和查看。
哪种方法更好:
- a) 在程序的入口点加载配置文件,并通过代码中的每个方法传递一大堆配置变量
- b) 在程序入口加载config文件,通过代码中的各个方法向下传递相关的config变量集合
- c) 在需要的地方直接加载配置变量
- d) 加载配置并使其成为全局
我愿意听取特定实施的建议或示例。目前我正在尝试嵌套配置变量,每个嵌套对象在代码中存储不同模块的配置。
我建议您执行以下步骤。
首先,使用支持多个 sections/scopes 概念的配置文件语法,最好是可嵌套范围。例如,XML 元素是我所说的可嵌套范围,而“.ini”文件提供不可嵌套的部分。 Java 属性文件不提供对范围的直接支持,但您可以通过使用语法 x.y.z
来表示范围 y
中的变量 z
来模拟此类支持,其中turn 嵌套在范围 x
中。 Config4*(我开发的)提供对嵌套作用域的直接支持。
其次,编写一个可配置的Foo
class的构造函数,如下伪代码所示:
Foo(Configuration cfg, String scope) {
_x = cfg.lookup(scope + ".x");
_y = cfg.lookup(scope + ".y");
_z = cfg.lookup(scope + ".z");
_bar = new Bar(cfg, scope + ".bar");
}
在上面的伪代码中,我使用 _
前缀来表示一个实例变量,我假设 Configuration
class 有一个 lookup()
操作需要范围名称,例如,cfg.lookup("foo.bar.abc")
将 return foo.bar
范围内的 abc
变量的值。
第三,你的应用程序的main()
函数可以写成如下伪代码所示:
main(...) {
String configFileName = ...; // obtain from command-line argument
String scope = ...; // obtain from command-line argument
Configuration cfg = parseConfigurationFile(configFileName);
Foo foo = new Foo(cfg, scope + ".foo");
... // create other configured objects
doRealWork(foo, ...);
}
最后,应用程序的命令行参数应指定:(1) 配置文件的名称,以及 (2) 包含 [=67] 配置变量的顶级范围(在配置文件中) =]宁应用程序。例如,假设 example.cfg
的结构如下:
instance1 {
foo {
x = "a value";
y = "another value";
z = "yet another value";
bar {
...
}
}
... # configuration for other objects
}
instance2 {
foo {
x = "...";
y = "...";
z = "...";
bar {
...
}
}
... # configuration for other objects
}
您可能 运行 您的应用程序 myApp.exe -cfg example.cfg -scope instance1
。
以上建议具有以下好处:
- 您的应用程序可以创建多个
Foo
对象,每个对象都可以进行不同的配置,只需将不同的scope
参数传递给每个对象的构造函数即可。 - 用户可以根据需要灵活地在单个配置文件中存储多组配置变量。例如,用户可能有不同的配置变量集用于:(1) 不同的单元测试; (2)开发、UAT和生产环境; (3) 复制服务器应用程序的多个实例。
- 随着时间的推移,您可以编写一个遵循上述设计原则的可配置 classes 库。该可配置 classes 库可以在多个应用程序中重复使用。
我已经在我编写的几个基于 C++ 和 Java Config4* 的应用程序中使用了上述方法,它对我来说效果很好。如果您使用的语言内置了反射支持(例如 Java),那么另一种方法是使用依赖注入框架。如果您不知道那是什么,请在 Internet 上搜索 "dependency injection"、"inversion of control" 或 "Spring Framework".