Как учитывать коэффициенты при сумме платежа 6000?
Что проверяют
Задача нарочно сформулирована расплывчато: интервьюер смотрит, начнёте ли вы с уточнений и как считаете деньги в Java. Следом обычно двигают границу («а если ровно 6000?») или просят добавить новый коэффициент без переписывания кода.
Как отвечать
Сначала уточните правила:
- как применяются коэффициенты: последовательно друг к другу, каждый к исходной сумме или по диапазонам, как в прогрессивной шкале, где к части до порога один коэффициент, а к остатку другой;
- граница: 6000 входит в верхний диапазон или в нижний. Это нужно зафиксировать и покрыть тестами 5999.99, 6000 и 6000.01;
- округление: на каждом шаге или только в конце, до копеек, по какому правилу. С фиксированными сборами и промежуточным округлением порядок операций начинает влиять на итог.
Дальше техника:
- тип:
BigDecimal, неdouble. Создавать из строки или черезBigDecimal.valueOf(...), а неnew BigDecimal(0.1), который унесёт двоичную погрешность. Альтернатива: хранить сумму в копейках какlong; - округление явно:
setScale(2, RoundingMode.HALF_UP)илиHALF_EVEN, как требует бизнес. Деление безMathContextили масштаба на бесконечной дроби броситArithmeticException; - сравнение:
compareTo, а неequals. Дляequalsзначения6000.0и6000.00разные, потому что у них разный масштаб; - расширяемость: пороги в
TreeMap<BigDecimal, BigDecimal>с поиском черезfloorEntry(amount)либо набор правил за общим интерфейсом (паттерн «Стратегия»), а значения в конфигурации, а не в коде.
Где спотыкаются
Считают в double и проверяют итог на глаз. Ошибка того же рода, что 0.1 + 0.2, в денежном расчёте превращается в копеечные расхождения при сверке.
Путают сложение коэффициентов с перемножением. Скидка 10% и надбавка 15% к 6000 дают 6210, а не 6300: коэффициенты 0.9 и 1.15 перемножаются, а не складываются в плюс пять процентов.
Жёстко вшивают порог и коэффициенты в if. Первое же изменение тарифа требует релиза, а граница 6000 почти наверняка окажется не с той стороны.