Я довольно прагматик, но моя главная проблема здесь в том, что вы можете позволить этому ConfigBlockдоминировать в дизайне вашего интерфейса, возможно, плохо. Когда у вас есть что-то вроде этого:
explicit MyGreatClass(const ConfigBlock& config);
... более подходящий интерфейс может быть таким:
MyGreatClass(int foo, float bar, const string& baz);
... вместо того, чтобы просто собирать эти foo/bar/bazполя из массива ConfigBlock.
Ленивый дизайн интерфейса
С другой стороны, этот вид дизайна позволяет легко создавать стабильный интерфейс для вашего конструктора, например, поскольку, если вам в конечном итоге понадобится что-то новое, вы можете просто загрузить это в ConfigBlock(возможно, без каких-либо изменений кода), а затем cherry- выбрать любой новый материал, который вам нужен, без какого-либо изменения интерфейса, только изменение реализации MyGreatClass.
Так что это как за, так и против, что это освобождает вас от разработки более тщательно продуманного интерфейса, который принимает только те входные данные, которые ему действительно необходимы. Он применяет мышление: «Просто дайте мне этот большой массив данных, я выберу из него то, что мне нужно», а не что-то вроде «Эти точные параметры - это то, что этот интерфейс должен работать».
Так что, безусловно, здесь есть некоторые плюсы, но они могут сильно перевесить минусы.
Связь
В этом сценарии все такие классы, создаваемые из ConfigBlockэкземпляра, в конечном итоге имеют зависимости:

Это может стать PITA, например, если вы хотите провести модульное тестирование Class2в этой диаграмме изолированно. Возможно, вам придется поверхностно смоделировать различные ConfigBlockвходные данные, содержащие соответствующие поля Class2, чтобы иметь возможность протестировать его в различных условиях.
В любом виде нового контекста (будь то модульное тестирование или целый новый проект) любые такие классы могут в конечном итоге стать более обременительным для (повторного) использования, поскольку в конечном итоге нам приходится всегда брать ConfigBlockс собой в поездку и настраивать его. соответственно.
Повторное использование / готовность к развертыванию / Тестируемость
Вместо этого, если вы спроектируете эти интерфейсы надлежащим образом, мы можем отделить их ConfigBlockи получить что-то вроде этого:

Если вы заметили на этой диаграмме выше, все классы становятся независимыми (их афферентные / исходящие связи уменьшаются на 1).
Это приводит к гораздо большему количеству независимых классов (по крайней мере, независимых ConfigBlock), которые намного проще (повторно) использовать / тестировать в новых сценариях / проектах.
Теперь этот Clientкод оказывается тем, который должен зависеть от всего и собирать все это вместе. Бремя в конечном итоге переносится в этот клиентский код для чтения соответствующих полей из ConfigBlockи передачи их в соответствующие классы в качестве параметров. Тем не менее, такой клиентский код, как правило, узко разработан для конкретного контекста, и его потенциал для повторного использования, как правило, будет в любом случае нулевым или закрытым (это может быть mainфункция точки входа вашего приложения или что-то в этом роде).
Таким образом, с точки зрения повторного использования и тестирования, это может помочь сделать эти классы более независимыми. С точки зрения интерфейса для тех, кто использует ваши классы, это также может помочь явно указать, какие параметры им нужны, а не только один массив, ConfigBlockкоторый моделирует весь набор полей данных, необходимых для всего.
Вывод
В общем, этот вид класс-ориентированного дизайна, который зависит от монолита, в котором есть все необходимое, как правило, имеет такие характеристики. Их применимость, возможность развертывания, возможность повторного использования, тестируемость и т. Д. Могут значительно ухудшиться. Тем не менее, они могут отчасти упростить дизайн интерфейса, если мы попытаемся сделать это положительно. Вы должны оценить эти плюсы и минусы и решить, стоят ли компромиссы того. Как правило, гораздо безопаснее ошибиться против такого дизайна, когда вы выбираете вишню из монолита в классах, которые обычно предназначены для моделирования более общего и широко применимого дизайна.
Последний, но тем не менее важный:
extern CodingBlock MyCodingBlock;
... это потенциально даже хуже (более искажено?) с точки зрения характеристик, описанных выше, чем подход с внедрением зависимостей, так как в итоге он связывает ваши классы не только с конкретным экземпляромConfigBlocks , но и непосредственно с ним. Это дополнительно ухудшает применимость / разворачиваемость / тестируемость.
Мой общий совет заключается в том, чтобы ошибаться при разработке интерфейсов, которые не зависят от этих типов монолитов, для предоставления их параметров, по крайней мере, для наиболее общих применимых классов, которые вы разрабатываете. И избегайте глобального подхода без внедрения зависимостей, если можете, если у вас нет действительно веской и уверенной причины не избегать этого.