Refactoring
The first thing I'd do is remove the redundant else
statements. If you return from every branch, then there's really no need for the else
clauses, they're just adding noise.
Constants?
It seems like there's some scope for constants / or lookups since there's some numbers floating around that seem to have meaning (discount amount, discount trigger threshold) etc. If you're labelling a number with a comment (baker's dozen), it's a good indication that it could be replaced with a constant to 'name' the value.
What are you really be looking for?
However, for me, I think the code actually serves more to prompt questions about whether or not it is performing as desired. If it is performing as expected, then it's the type of pricing system I hate (because it relies on the customer to optimize their own purchases).
If I buy 12 items, I'm charged for 12 at the discounted rate.
If I buy 13, I'm charged for 12 items at the standard rate.
If I buy 14, I'm charged for 14 at the discounted rate. This is more expensive than me buying 13, then buying a single item as a separate transaction.
Is this correct? Are you hitting me with the postage? Why don't I get 26 for the price of 24?
etc...
Constants Revisited
I think some of the above contribute to your difficulty coming up with constants... I'd go with something like this:
private static double getTotalPrice(int quantity, double itemPrice) {
if (quantity == SPECIAL_ONE_OFF_DISCOUNT_QUANTITY) {
return itemPrice * (SPECIAL_ONE_OFF_DISCOUNT_QUANTITY - 1);
}
if (quantity >= TRIGGER_DISCOUNT_QUANTITY) {
return itemPrice * quantity * DISCOUNT_MULTIPLIER;
}
return itemPrice * quantity;
}
I'm using 'SPECIAL_ONE_OFF_DISCOUNT_QUANTITY', because it really is a special one off amount, with the current logic. It doesn't duplicate at 26 etc. I've got rid of the '12' constant, because really it's just 1 less than the trigger amount. Having a 'ONE_OFF_DISCOUNTTED_QUANTITY' constant might make sense if you could see the need to pay for 10 when you bought 13 for example, however this seems a it unnecessary.
As I said, I'd prefer to rework the logic so that you always pay the lowest amount + so that discounts are additive. This changes the output prices, so obviously wouldn't be possible if it didn't actually make sense to the client. It does allow some of the constants to have different names though:
private static double getTotalPrice(int quantity, double itemPrice) {
var chargeableQuantity = quantity - quantity / BUY_X_GET_ONE_FREE_QUANTITY;
var valueMultiplier = chargeableQuantity >= TRIGGER_DISCOUNT_QUANTITY ? DISCOUNT_MULTIPLIER : 1;
return itemPrice * chargeableQuantity * valueMultiplier;
}
I think 'BUY_X_GET_ONE_FREE_QUANTITY' is a better name than 'SPECIAL_ONE_OFF_DISCOUNT_QUANTITY', but it only really makes sense if buying twice the amount results in twice the discount...
BigDecimal
. Effective Java is my Bible, and that is Psalm -- I mean Item -- 60. \$\endgroup\$BigDecimal
only makes sense for very specific situations where you do a loooong list of calculations on some values and want to keep a specific property. For things like a simple price using a fixed point number will work just as well. In your use case using a double and rounding at the end to the actual significant digits (2 or maybe 3 for most use cases) will give exactly the same result. \$\endgroup\$14 * .95 * itemPrice
. Is that correct? Or should it be13 * itemPrice
? Or12.95 * itemPrice
? Note that a customer could achieve the second price simply by making two separate purchases. In the future, please provide a problem statement for what the code is supposed to solve. \$\endgroup\$