Как разработать программу с множеством вариантов конфигурации? - PullRequest
13 голосов
/ 07 сентября 2011

Допустим, у меня есть программа с большим количеством опций конфигурации. Пользователь может указать их в конфигурационном файле. Моя программа может анализировать этот файл конфигурации, но как он должен внутренне хранить и передавать параметры?

В моем случае программное обеспечение используется для проведения научного моделирования. Есть около 200 вариантов, большинство из которых имеют нормальные значения по умолчанию. Обычно пользователь должен указать только дюжину или около того. Сложность, с которой я сталкиваюсь, заключается в том, как разработать свой внутренний код. Многие из объектов, которые должны быть построены, зависят от многих параметров конфигурации. Например, для объекта могут потребоваться несколько путей (для которых будут храниться данные), некоторые параметры, которые необходимо передать в алгоритмы, которые будет вызывать объект, и некоторые параметры, которые используются непосредственно самим объектом.

Это приводит к тому, что объектам требуется очень большое количество аргументов для построения. Кроме того, поскольку моя кодовая база находится в стадии очень активной разработки, очень трудно пройти через стек вызовов и передать новую опцию конфигурации вплоть до того места, где это необходимо.

Одним из способов предотвратить эту боль является наличие объекта глобальной конфигурации, который можно свободно использовать в любом месте кода. Мне не особенно нравится этот подход, так как он приводит к функциям и классам, которые не принимают (или только один) аргумент, и для читателя не очевидно, с какими данными имеет дело функция / класс. Это также предотвращает повторное использование кода, так как весь код зависит от гигантского объекта конфигурации.

Кто-нибудь может дать мне несколько советов о том, как следует структурировать такую ​​программу?

Вот пример того, что я имею в виду для стиля передачи опции конфигурации:

class A:
    def __init__(self, opt_a, opt_b,  ..., opt_z):
        self.opt_a = opt_a
        self.opt_b = opt_b
        ...
        self.opt_z = opt_z

    def foo(self, arg):
        algo(arg, opt_a, opt_e)

Вот пример глобального стиля конфигурации:

class A:
    def __init__(self, config):
        self.config = config

    def foo(self, arg):
        algo(arg, config)

Примеры написаны на Python, но мой вопрос касается любого подобного языка программирования.

Ответы [ 4 ]

5 голосов
/ 07 сентября 2011

matplotlib - это большой пакет с множеством опций конфигурации.Он использует модуль rcParams для управления всеми параметрами по умолчанию.rcParams сохраняет все параметры по умолчанию в формате.

Каждая функция получит параметры из аргументов ключевого слова:

, например:

def f(x,y,opt_a=None, opt_b=None):
    if opt_a is None: opt_a = rcParams['group1.opt_a']
3 голосов
/ 07 сентября 2011

Несколько шаблонов дизайна помогут

  • Прототип
  • Фабрика и абстрактная фабрика

Используйте эти два шаблона с объектами конфигурации. Каждый метод будет тогда брать объект конфигурации и использовать то, что ему нужно. Также рассмотрите возможность применения логической группировки для настройки параметров и подумайте о способах уменьшения количества входов.

код псевдо

// Consider we  can run three different kinds of Simulations. sim1, sim2, sim3

ConfigFactory configFactory = new ConfigFactory("/path/to/option/file");
....
Simulation1 sim1;
Simulation2 sim2;
Simulation3 sim3;

sim1.run( configFactory.ConfigForSim1() );
sim2.run( configFactory.ConfigForSim2() );
sim3.run( configFactory.ConfigForSim3() );

Внутри каждого метода фабрики он может создавать конфигурацию из объекта-прототипа (который имеет все «нормальные» значения по умолчанию), и файл опций становится просто тем, что отличается от значения по умолчанию. Это будет связано с четкой документацией о том, что представляют собой эти значения по умолчанию и когда человек (или другая программа) может захотеть изменить их.

** Редактировать: ** Также учтите, что каждая конфигурация, возвращаемая фабрикой, является подмножеством общей конфигурации.

2 голосов
/ 07 сентября 2011

Передайте либо класс синтаксического анализа конфигурации, либо напишите класс, который оборачивает его и разумно извлекает запрошенные параметры.

Стандартная библиотека Python configparser предоставляет разделы и параметры файла конфигурации в стиле INI с использованием протокола сопоставления, поэтому вы можете извлекать свои параметры непосредственно из этого, как если бы это был словарь.

myconf = configparser.ConfigParser()
myconf.read('myconf.ini')
what_to_do = myconf['section']['option']

Если вы явно хотите предоставить опции, используя обозначение атрибута, создайте класс, который переопределяет __getattr__:

class MyConf:
    def __init__(self, path):
        self._parser = configparser.ConfigParser()
        self._parser.read('myconf.ini')
    def __getattr__(self, option):
        return self._parser[{'what_to_do': 'section'}[option]][option]

myconf = MyConf()
what_to_do = myconf.what_to_do
0 голосов
/ 07 сентября 2011

Пусть модуль загрузит параметры в свое пространство имен, затем импортирует их и использует их в любом месте.
Также см. Связанный вопрос здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...