Как управлять конфигурацией классов и распространять ее на более глубокие уровни

У меня есть несколько классов, которые должны взаимодействовать. В каждом классе много опции это можно настроить, чтобы получить то или иное поведение.

(нота: Я не тестировал код, поэтому может быть какая-то синтаксическая ошибка)

(заметка 2: Я пишу на PHP, но я думаю, что этот вопрос актуален и для каждого языка ООП)

<?php

class Process
{
protected $element;
protected $config;
protected $default_config = array(
'process_path' => '/bin/command',
'default_output_path' => '/tmp/',
'element_conf' => array()
);

public function __construct(array $config)
{
$this->config = $config;
$element_config = array_key_exists('element_conf', $this->config)
? $this->config['element_conf']
: array();
$this->element = new Element($element_config);
}

public function run()
{
$this->element->behave();

// ...
}

// ...
}

class Element
{
protected $type;
protected $config;
protected $default_config = array(
'behaviour_type' => 'evil',
'can_kill_people' => true
);

public function __construct(array $config)
{
$this->config = array_replace($this->default_config, $config);
$this->type = $this->config['behaviour'];
}

public function behave()
{
// ...
}

// ....
}

class Config
{
// get data from config file and makes it available with a static getter/setter
}

-------------------------------

$element_conf = array(
'can_kill_people' => false
);
$process_conf = array(
'default_output_path' => Config::get('default_output_path'),
'element_conf' => $element_conf
);

$pr = new Process($process_conf);
$pr->run();

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

Я хотел бы получить ваши мысли о:

  • В способе предусмотрена конфигурация для внутреннего класса (Элемент). Я хотел бы инициализировать его конфигурации на верхнем уровне
    (перед вызовом run() метод); но я не нахожу хороший способ
    конфигурация для Элемент зависит от кода из
    Процесс.

  • Способ предоставления конфигурации для класса. Будет ли лучше передать / установить массив Конфиг, как в моем коде, или
    я должен передать каждый параметр в качестве аргумента конструктора, или установить его с
    сеттер?

  • Сохраните ли вы конфигурацию в защищенный собственность, как массив? Или вы бы назначить каждый соответствующий параметр для одного защищенный / частный имущество?
    (как я сделал для Element::type)

  • Каков ваш обычный подход к управлению конфигурациями класса? Будете ли вы пытаться иметь класс также для хранения конфиграции? Вы бы предпочли массивы? Или передача / установка аргументов / свойств напрямую? (этот последний подход, на мой взгляд, не так легко поддерживать).
    Или даже лучше шаблон дизайна существует специально для этого случая?

0

Решение

Если ваш класс процесса должен быть параметризован объектом Element, передайте объект Element в качестве параметра, а не его параметры в качестве параметра. Этот подход также подчеркивает, что класс Process зависит от класса Element, который не сразу виден из конструктора Process.

Что касается конфигурации массива — по моему мнению, использование массивов легко писать, но затрудняет фактическое использование класса, как вы легко узнаете, какие настройки поддерживает ваш класс? Я бы предпочел использовать либо отдельные параметры в конструкторе, либо отдельный класс конфигурации с определенными свойствами.

То, как вы делаете вещи внутри самого класса, на самом деле не имеет большого значения, пока вы заключаете это в какой-то разумный публичный интерфейс. Что вы хотите сделать, так это сохранить как можно больше вещей в секрете, чтобы сохранить возможность изменять внутреннюю работу класса, если это необходимо, при этом поддерживая обратно совместимый общедоступный интерфейс. Также имейте в виду, что защищенный — это почти то же самое, что и общедоступный, когда вы можете изменить его, не нарушая обратной совместимости, поскольку защищенные свойства и методы могут использоваться дочерними классами.

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

1

Другие решения

Не существует лучшего способа сделать что-то глобально, есть лучший способ сделать то, что вы хотите (универсальный или нет) (примените первое утверждение: D).

Конфиг по умолчанию

Элемент конфигурации может быть обязательным или нет, но всегда должен иметь значение по умолчанию (поэтому он может быть не обязательным).
На мой взгляд, есть 2 способа предоставить значение по умолчанию:

  1. Декларативный способ
    Когда вы создаете экземпляр объекта конфигурации, вы предоставляете все значения по умолчанию, но динамические значения невозможны, если источник не является динамическим.
  2. «Встроенный» способ
    Вы предоставляете значение по умолчанию, когда запрашиваете текущее значение.

Но на самом деле вы можете использовать оба, используя свои собственные правила.

Используя эти правила, вы можете указать значение по умолчанию для конфигурации вашего элемента. Но его текущая конфигурация может быть предоставлена ​​как субконфигурация или другой источник … который может использовать Process.

Декларативная конфигурация

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

В моей структуре все конфигурации хранятся в виде массивов в защищенном члене класса Config. Это связано с тем, что мне нужна универсальность, но я не допускаю пропущенных значений в конфигурационных файлах.

ООП позволяет только ООП

Когда вы используете ООП, используйте его как можно чаще, объект является экземпляром класса, класс объявлен, вы знаете, что означает его содержимое. Вы не можете делать общие источники, если вы не используете объекты.

1

По вопросам рекламы [email protected]