Спуск контента вызова внутрь процедуры
Вообще-то я программирую в 1С, на языке, похожем на Visual Basic. Но мне кажется, что затронутый в этой теме вопрос касается всех языков программирования, т.к. затрагивает проблему, с которой рано или поздно сталкивается программист при работе со сложным кодом.
Суть ситуации заключается в том, что есть некая процедура, которая делает расчет или выполняет какие-то действия. Возникшие изменения требуют, чтобы в некоторых случаях этот расчет или действия отличались в зависимости от того, из какого контекста вызывается данная процедура.
Приведу пример, где после изменений требуется, чтобы выводилась не сумма y и z, а эта сумма, умноженная на некоторый коэффициент c, который вводится на верхнем уровне, в процедуре Top.
Исходный код:
sub Top()
Middle
end sub
sub Middle()
y = get1
z = get2
Down y, z
end sub
sub Down(y, z)
echo y+z
end sub
Проблему можно решить передачей дополнительного параметра c, но если цепочка процедур длинная, это вызовет слишком обширные изменения во многих промежуточных процедурах:
sub Top()
Input c
Middle c
end sub
sub Middle(c)
y = get1
z = get2
Down y, z, c
end sub
sub Down(y, z, c)
echo (y+z)*c
end sub
Неплохо, если автор процедуры сделал переменную-структуру k для хранения контекста вызова, куда можно добавлять произвольные поля, тогда задача решается просто:
sub Top()
Input c
k = strukt
k.add "c", c
Middle k
end sub
sub Middle(k)
y = get1
z = get2
Down k, y, z
end sub
sub Down(k, y, z)
echo (y+z)*c
end sub
Но, практика показывает, что такая забота и предусмотрительность встречаются не так часто.
Поэтому на практике я применяю другой подход:
sub Top()
Input c
global.add "c", c
Middle
end sub
sub Middle()
y = get1
z = get2
Down y, z
end sub
sub Down(y, z)
echo (y+z)*global.c
end sub
Здесь global - это некоторая глобальная структура, которая хранит глобальные данные текущего сеанса пользователя, у каждого пользователя своя. Конкретно в 1С - это параметры сеанса.
Такой подход требует внимательной проверки на реентерабельность, но в целом, довольно часто успешно решает проблему.
Непосредственно методику использовал в двух случаях:
В процедуре рассчитывалась зарплата исходя из учтенного для сотрудника времени. Но клиенту для расчета авансов понадобилось начислять зарплату не по фактическому, а по плановому времени. Вид времени определялся из вида документа - аванс или окончательная оплата. А после этого должен был как-то попадать в функцию расчета зарплаты. Тут и пригодилась методика.
В некоторых печатных формах нужно было изменить наименование.
В процедуре, где выводилось наименование не было сведений о том, из какого документа печатается наименование, а наименование должно было обрабатываться исходя из вида документа (внутренний или клиенту). Я использовал передачу параметров описанным выше методом.
Что скажете насчет способа? Использовали? Или что можно предложить взамен? А может быть некоторые языки поддерживают такую передачу контекста вызова "играючи"? Хотелось бы взглянуть.