patternjavaMinor
Calculating the number of candy bars and gumballs that can be redeemed using coupons
Viewed 0 times
cannumberthecandygumballsredeemedcouponscalculatingthatusing
Problem
The following question was taken from Absolute Java 5th ed. by Walter Savitch:
The video game machines at your local arcade output coupons according to how well you play the game. You can redeem 10 coupons for a candy bar or 3 coupons for a gumball. You prefer candy bars to gumballs. Write a program that defines a variable initially assigned to the number of coupons you win. Next, the program should output how many candy bars and gumballs you can get if you spend all of your coupons on candy bars first, and any remaining coupons on gumballs.
This is the code that I have written:
The video game machines at your local arcade output coupons according to how well you play the game. You can redeem 10 coupons for a candy bar or 3 coupons for a gumball. You prefer candy bars to gumballs. Write a program that defines a variable initially assigned to the number of coupons you win. Next, the program should output how many candy bars and gumballs you can get if you spend all of your coupons on candy bars first, and any remaining coupons on gumballs.
This is the code that I have written:
public class Question2 {
private static final int NUMBER_OF_COUPONS_FOR_A_CANDYBAR = 10;
private static final int NUMBER_OF_COUPONS_FOR_A_GUMBALL = 3;
private static int numberOfCoupons = 13;
public static void main(String[] args) {
System.out.println(numberOfCandybars(numberOfCoupons)
+ " candybar(s) and " + numberOfGumballs(numberOfCoupons)
+ " gumball(s).");
}
private static int numberOfCandybars(int initialCoupons) {
return initialCoupons / NUMBER_OF_COUPONS_FOR_A_CANDYBAR;
}
private static int numberOfGumballs(int remainingCoupons) {
remainingCoupons = numberOfCoupons % NUMBER_OF_COUPONS_FOR_A_CANDYBAR;
return remainingCoupons / NUMBER_OF_COUPONS_FOR_A_GUMBALL;
}
}Solution
Looking at this statement, it looks as if
But they are not independent, because
If you think about it, it would be best if
With these two values, we could use the number of coupons left to make another call to
Of course, Java can only return a single value. But the single value can be an object, which can contain multiple values.
So let's start over. We have items: Candy bar, Gumball. We have some kind of a vending machine, that you put coupons into, select the item you want, and it gives back a number of items and change (remaining coupons).
Let's model the items with an
And let's model the machine and the output it gives:
This seems a more natural, flexible and extensible design. Now we can rewrite the original statement like this:
numberOfGumballs and numberOfCandybars are independently derived from numberOfCoupons:System.out.println(numberOfCandybars(numberOfCoupons)
+ " candybar(s) and " + numberOfGumballs(numberOfCoupons)
+ " gumball(s).");But they are not independent, because
numberOfGumballs actually depends on numberOfCoupons and numberOfCandybars too. Hiding this fact is not a good thing: one might expect that changing the behavior of numberOfCandybars won't affect the behavior of numberOfGumballs, but it actually will, which is confusing.If you think about it, it would be best if
numberOfCandybars returned 2 values:- The number of candy bars our coupons could buy
- and, the number of coupons left
With these two values, we could use the number of coupons left to make another call to
numberOfGumballs, and keep the number of candy bars for printing later. That way, the relationships between the functions could be well visible.Of course, Java can only return a single value. But the single value can be an object, which can contain multiple values.
So let's start over. We have items: Candy bar, Gumball. We have some kind of a vending machine, that you put coupons into, select the item you want, and it gives back a number of items and change (remaining coupons).
Let's model the items with an
enum, and give them a price too.enum Item {
CandyBar(10),
Gumball(3);
final int price;
Item(int price) {
this.price = price;
}
}And let's model the machine and the output it gives:
class AutomaticCandyMachineOutput {
final Item item;
final int itemCount;
final int change;
AutomaticCandyMachineOutput(Item item, int itemCount, int change) {
this.item = item;
this.itemCount = itemCount;
this.change = change;
}
}
class AutomaticCandyMachine {
AutomaticCandyMachineOutput redeemCouponsForItems(int coupons, Item item) {
int itemCount = coupons / item.price;
int change = coupons % item.price;
return new AutomaticCandyMachineOutput(item, itemCount, change);
}
AutomaticCandyMachineOutput redeemCouponsForCandybars(int coupons) {
return redeemCouponsForItems(coupons, Item.CandyBar);
}
AutomaticCandyMachineOutput redeemCouponsForGumballs(int coupons) {
return redeemCouponsForItems(coupons, Item.Gumball);
}
}This seems a more natural, flexible and extensible design. Now we can rewrite the original statement like this:
int coupons = 99;
AutomaticCandyMachine machine = new AutomaticCandyMachine();
AutomaticCandyMachineOutput output1 = machine.redeemCouponsForCandybars(coupons);
AutomaticCandyMachineOutput output2 = machine.redeemCouponsForGumballs(output1.change);
String.format(
"%d candybar(s) and %d gumball(s)",
output1.itemCount,
output2.itemCount);Code Snippets
System.out.println(numberOfCandybars(numberOfCoupons)
+ " candybar(s) and " + numberOfGumballs(numberOfCoupons)
+ " gumball(s).");enum Item {
CandyBar(10),
Gumball(3);
final int price;
Item(int price) {
this.price = price;
}
}class AutomaticCandyMachineOutput {
final Item item;
final int itemCount;
final int change;
AutomaticCandyMachineOutput(Item item, int itemCount, int change) {
this.item = item;
this.itemCount = itemCount;
this.change = change;
}
}
class AutomaticCandyMachine {
AutomaticCandyMachineOutput redeemCouponsForItems(int coupons, Item item) {
int itemCount = coupons / item.price;
int change = coupons % item.price;
return new AutomaticCandyMachineOutput(item, itemCount, change);
}
AutomaticCandyMachineOutput redeemCouponsForCandybars(int coupons) {
return redeemCouponsForItems(coupons, Item.CandyBar);
}
AutomaticCandyMachineOutput redeemCouponsForGumballs(int coupons) {
return redeemCouponsForItems(coupons, Item.Gumball);
}
}int coupons = 99;
AutomaticCandyMachine machine = new AutomaticCandyMachine();
AutomaticCandyMachineOutput output1 = machine.redeemCouponsForCandybars(coupons);
AutomaticCandyMachineOutput output2 = machine.redeemCouponsForGumballs(output1.change);
String.format(
"%d candybar(s) and %d gumball(s)",
output1.itemCount,
output2.itemCount);Context
StackExchange Code Review Q#62390, answer score: 4
Revisions (0)
No revisions yet.