Здравствуйте, Quebecois, Вы писали:
Q>Если Calculate() хоть сколько-либо нетривиально, лишнее выделение памяти здесь погоды не сделает.
out string выглядит как кандидат на логирование или на что еще, с выводом промежуточных результатов куда либо. Лично я для этого использую подход шины сообщений. В случае, если я живу без DI IOC фреймворков, у меня есть глобальный доступный отовсюду объект eventBus, с двумя методами — publish и subscribe (ладно, трeмя — unsubscribe может еще потребоваться). Соответственно там, где нужно уведомить внешний код, я в расчетной части буду кидать соответствующие события. Ну а если я уже живу с фреймворками, то функционал шины сообщений там как правило уже встроен, ну и у меня уже никаких статиков — все классы конструируются и инжектятся зависимости уже фреймворком, соответственно у меня вообще никаких new в коде практически нет.
Собственно с точки зрения внешнего кода подход с классом все равно чуть более громоздкий — один хрен нужно передавать параметры, теперь м их передаем в конструкторе и можем еще дополнительно просетать всякие второстепенные параметры отдельно. Преимуществ подобного подхода особо не вижу. А если мы останавливаемся на статике и не хотим в промежуточные функции передавать до черта аргументов — мы внутри статического метода конструируем объект (точнее даже структуру зачастую, ибо методы не нужны) контекста выполнения и уже контекст выполнения передаем на подрасчеты. Но при этом вся сложность и все проблемы самого расчета клиента вызывающего кода не касаются никак, для вызывающего кода это чистая функция без сайдэффектов.
Есть конечно еще один подход — параметры передавать через билдеры, возвращая ссылку на сам билдер чтобы можно было в цепочку инициализации выстраивать. Но такое ИМХО нужно использовать далеко не по умолчанию и 100 раз подумать, нужно таким заморачиваться или нет смысл усложнять клиентский код, лично я такое считаю оправданным только в какой тяжелой библиотеке на этапе инициализации один раз во всем приложении.