Для опций, которые включают / выключают функциональность, я думаю, что Decorator - это то, что нужно, как говорит @Thomas Owens. Я немного больше обеспокоен опциями, которые меняют функции. Декоратор много не работает, если эти операции не могут быть связаны. Например, если ваш код выглядит так:
public void ActionABC()
{
if (options.DoA)
{
A();
}
if (options.DoB)
{
B();
}
if (options.DoC)
{
C();
}
}
public void ActionCAB()
{
if (options.DoC)
{
C();
}
if (options.DoA)
{
A();
}
if (options.DoB)
{
B();
}
}
Это было бы трудно решить с помощью Decorator, поскольку порядок композиции для каждого метода действия различается.
С 20+ опциями, при условии, что они включены / выключены, у вас есть более 400 различных возможных комбинаций. Я подозреваю, что не все из этих комбинаций одинаково вероятны. Для вещей, которые вы не можете обработать с помощью Decorator, вы можете подумать о режимах работы, которые соответствуют комбинациям настроек. Поддержка только тех режимов, которые наиболее ожидаемы. Если количество режимов невелико, вы можете обработать это с помощью подклассов, а затем использовать декораторы, чтобы добавить функциональность в подкласс, представляющий режим, выбранный пользователем. Вы можете использовать Factory, чтобы выбрать и построить подходящий класс на основе конфигурации.
По сути, я предполагаю, что, возможно, вы захотите подумать, нужно ли вам столько гибкости и сопутствующей сложности, сколько вы строите. Подумайте об уменьшении количества параметров конфигурации, сворачивая их в меньшее число наиболее вероятных используемых режимов.