Настройки уровня приложения в DDD?

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

В частности, я имею в виду настройки высокого уровня, которые могут быть изменены администратором. такие вещи, которые вы можете хранить в приложении или web.config в конечном итоге, но с точки зрения DDD должны быть явно установлены где-то в объектах.

В качестве примера возьмем веб-систему управления контентом или приложение для блога.

У данной сущности записи блога есть любое количество настроек экземпляра, таких как автор, контент и т. д.

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

Итак, мои мысли следующие:

1) используйте свойства уровня класса (статические) для представления этих настроек, а затем установите их при запуске приложения, установив их либо из БД, либо из web.config.

or

2) использовать отдельный объект для хранения настроек, возможно, словарь, либо использовать его напрямую, либо сделать его членом класса Entry

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


person Paul    schedule 23.11.2009    source источник


Ответы (1)


Я бы сказал, что то, является ли значение настраиваемым или нет, не имеет значения с точки зрения модели предметной области - важно то, что оно определено извне.

Допустим, у вас есть класс, который должен иметь имя. Если имя требуется всегда, оно должно быть инкапсулировано как инвариант независимо от источника значения. Вот пример С#:

public class MyClass
{
    private string name;

    public MyClass(string name)
    {
        if(name == null)
        {
            throw new ArgumentNullException("name");
        }

        this.name = name;
    }

    public string Name
    {
        get { return this.name; }
        set
        {
            if(value == null)
            {
                throw new ArgumentNullException("name");
            }
            this.name = value;
        }
    }
}

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

Но вы спросили о значениях по умолчанию. Если у вас есть хорошее значение по умолчанию для имени, то как вы передаете это значение по умолчанию MyClass.

Вот где Фабрики пригодятся. Вы просто отделяете построение своих объектов от их реализации. Часто это хорошая идея в любом случае. Независимо от того, выберете ли вы абстрактную фабрику или реализацию Builder, менее важно, но абстрактная фабрика — хороший выбор по умолчанию.

В случае с MyClass мы могли бы определить интерфейс IMyClassFactory:

public interface IMyClassFactory
{
    MyClass Create();
}

Теперь вы можете определить реализацию, которая извлекает имя из файла конфигурации:

public ConfigurationBasedMyClassFactory : IMyClassFactory
{
    public MyClass Create()
    {
        var name = ConfigurationManager.AppSettings["MyName"];
        return new MyClass(name);
    }
}

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

person Mark Seemann    schedule 24.11.2009
comment
Значения по умолчанию были примером, возможно, плохим; Я знаком с шаблоном Factory. Другим примером может быть что-то, что должно применяться ко всем экземплярам класса, но может измениться на уровне приложения. Возможно, что-то вроде количества экземпляров для загрузки в список (всегда) или правила о том, показывать или нет комментарии. На самом деле они не кажутся мне значениями уровня экземпляра, или я что-то неправильно понимаю? - person Paul; 24.11.2009
comment
Вы всегда можете инкапсулировать одно или несколько связанных значений в тип, а затем внедрить экземпляр этого типа во все потребители. Из соображений эффективности (или любых других причин) вы можете внедрить один общий экземпляр, в то время как потребители не имеют представления о времени жизни внедренного объекта. Это будет держать ваши варианты открытыми. - person Mark Seemann; 24.11.2009
comment
@MarkSeemann Что, если я хочу иметь настраиваемую логику в моей богатой модели предметной области? Например, простая настройка bool для определения метода расчета. Должен ли я также передать это логическое значение в конструкторе? - person Konrad; 13.09.2018
comment
@Конрад Возможно. Как объясняет Чистый код, логические флаги редко являются признаком хорошего дизайна. Часто полиморфизм может быть предпочтительнее, но, в конечном счете, разработка программного обеспечения заключается в взвешивании множества проблем, поэтому не может быть окончательных ответов без обширных знаний конкретных контекстов. - person Mark Seemann; 13.09.2018
comment
@MarkSeemann, на самом деле не имеет значения, логическое это значение или что-то еще, но скажем, это какая-то настройка, которая определяет, как рассчитываются цены. Я думаю, что должен быть какой-то общий ответ на это. - person Konrad; 13.09.2018
comment
@Konrad Если объект домена зависит от чего-то еще, будь то логическое значение или что-то более сложное, разве это не часть инвариантов объекта домена? В частности, разве это не предварительное условие? Если это так, если вы не передадите его через конструктор, то как вы собираетесь гарантировать этот инвариант? - person Mark Seemann; 13.09.2018
comment
@MarkSeemann Статическая переменная конфигурации? Но мне нужно как-то гарантировать безопасность потоков. В моей системе мне нужен глобальный параметр, определяющий, как обрабатывать определенные вычисления. Эти расчеты происходят внутри моделей предметной области. И этот параметр относится не только к одной модели предметной области, но и ко всему приложению или ко всем моделям предметной области, для которых требуются эти вычисления. - person Konrad; 13.09.2018
comment
Я не могу просто вводить конфигурацию в свои модели предметной области, потому что это кажется неправильным. Но мне нужен доступ к нему. Я думаю, что одним из решений было бы добавить параметр для моего метода, который выполняет эти вычисления, чтобы выбрать тип расчета. Так что это было бы похоже на CalculateSomething(CalculationMethod calculationMethod), но тогда мне нужно было бы читать это и передавать это каждый раз вручную. - person Konrad; 13.09.2018
comment
Итак, что я хотел сделать, так это установить этот CalculationMethod только 1 раз, не передавая ничего моему методу или модели предметной области. - person Konrad; 13.09.2018
comment
@Konrad AFAICT, здесь больше одной проблемы. Это слишком сложный вопрос, чтобы задавать его в этих комментариях, но если вы зададите новый вопрос, я буду рад взглянуть, если вы отправите мне ссылку. - person Mark Seemann; 14.09.2018
comment
@MarkSeemann stackoverflow. ком/вопросы/52327508/ - person Konrad; 14.09.2018