Posted by Marta on February 2, 2023 Viewed 44795 times
In this article, you will learn how to design a vending machine in Java step by step. This vending machine is a simple text-based program, meaning you will interact with the vending machine using the console and entering text.
In this tutorial, you will see the full development process for a straightforward program. Learn more about the software development process here.
The first step is defining the requirements or defining how the vending machine java program should work. We will create use cases and UML diagrams to define and clarify these requirements.
Next, we will see how to create a skeleton implementation following an object-oriented programming approach. Creating a skeleton implementation means creating some classes and interfaces, but we won’t write all the code yet. This step will help to organize the code.
And finally, we will complete the implementation. While writing the code, I will recommend following the clean code rules shared in the following post: 4 Simple Tricks to Write Java Clean Code
Let’s get started!
In this phase, we will refine how our Vending Machine java program will work using use cases and UML diagrams. Programming a Vending Machine is quite a vague statement. Therefore this step of the process is essential since it helps define how the program will work more concretely.
Let’s start by creating a use case:
Above you can see in bold some of the entities in this problem and highlighted the potential operations. Using these entities and operations, we can create a flow diagram that helps us to visualize how the entities will communicate:
At this point, we have a much better understanding of how the application should work. Here are the classes:
Main
VendingMachineInterface
VendingMachineController
Calculator
Coin
and CoinBundle
Product
The Main
class will start the program and coordinate the communication between the user and the VendingMachineInterface.
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner scanner = new Scanner(System.in); // TODO To complete in step3 VendingMachineInterface machineInterface = null; machineInterface.displayProducts(); String selectedProduct = scanner.nextLine(); machineInterface.selectProduct(Integer.parseInt(selectedProduct)); machineInterface.displayEnterCoinsMessage(); String userEnteredCoins = scanner.nextLine(); int[] enteredCoins = {}; // TODO Complete in step 3 machineInterface.enterCoins(enteredCoins); machineInterface.displayChangeMessage(); } }
The VendingMachineInterface
is the class that defines how to communicate with the user. In this case, we will communicate using text through the console; therefore, the class will display text messages and receive user text input, like the product selected or the coins.
public interface VendingMachineInterface { void displayProducts(); void selectProduct(int product); void displayEnterCoinsMessage(); void enterCoins(int... coins); void displayChangeMessage(); }
Another important class is the Calculator
. The calculator class will carry out operations to work out the total amount inserted and the minimum coins to return a change amount.
public interface Calculator { int calculateTotal(CoinBundle enteredCoins); CoinBundle calculateChange(int amountMoneyToReturn); }
Next, we will create a VendingController
class that coordinates the communication between the interface and the calculator. This class helps decouple the interface from the rest of the program. The interface doesn’t need to know how to calculate the change; it only needs to know where to request it.
public interface VendingMachineController { CoinBundle calculateChange(VendingMachineRequest request); }
public class VendingMachineRequest { public Product product; public CoinBundle enteredCoins; public VendingMachineRequest(int selectedProduct, int... enteredCoins){ // TODO Complete in step 3 this.product = null; this.enteredCoins = new CoinBundle(enteredCoins); } }
The Coin
class will represent all coins accepted by the machine: 5 cents, 10 cents, 20 cents, 50 cents, and 100 cents.
public enum Coin { FIVE_CENTS(5), TEN_CENTS(10), TWENTY_CENTS(20), FIFTY_CENTS(50), HUNDRED_CENTS(100); private int value Coin(int value){ this.value = value; } public int getValue(){ return this.value; } }
Next, since we will receive a bunch of coins and return a bunch of coins, we could represent a class instead of passing around an array of numbers representing the number of coins. This change will make communication between classes simpler. We will call this class CoinBundle
.
public class CoinBundle { public int number5CentsCoins; public int number10CentsCoins; public int number20CentsCoins; public int number50CentsCoins; public int number100CentsCoins; public CoinBundle(int... enteredCoins) { this.number5CentsCoins = enteredCoins[0]; this.number10CentsCoins = enteredCoins[1]; this.number20CentsCoins = enteredCoins[2]; this.number50CentsCoins = enteredCoins[3]; this.number100CentsCoins = enteredCoins[4]; } }
And finally, the Product
class that will define the product that this vending machine offers. In this instance, our vending machine sells Twix chocolate bars, Coke, Water, and Sandwiches. This class has two pieces of information: the selection number to buy the product and the price.
public enum Product { TWIX(1,100), COKE(2,50), WATER(3,30), SANDWICH(4,150), EMPTY(0,0); private int selectionNumber; private int price; Product(int selectionNumber, int price){ this.selectionNumber = selectionNumber; this.price = price; } public int getSelectionNumber(){ return selectionNumber; } public int getPrice(){ return this.price; } }
So far, we have eight classes representing all entities in our program, and we have clearly defined each class’s responsibilities. What is left to do now is filling up the gap; in other words, implementing the interface with the real code.
Completing the implementation is the last step in our software development process. By now, we have a clear picture of how the program will look and how the code distributes across the different classes.
Since previously we defined some interfaces, now we will implement these interfaces. First, we will override these interfaces with concrete classes and methods that indicate to the program how to perform those interface operations.
VendingMachineInterface
Let’s start by implementing the VendingMachineInterface
. The VendingMachineInterface
is the class that will communicate with the user. Since it is a text-based interface, I will call it TextVendingMachineInterface
. Consequently we need to write five methods:
displayProducts()
: this method displays a message in the console welcoming the user and showing the available products.selectProduct(int product)
: it receives the product selected by the user.displayEnterCoinsMessage()
: method that displays a message requesting the user to enter coins.enterCoins(int... coins)
: it receives the coins entered by the user.displayChangeMessage()
: it displays a message letting the user know his change amount and coins.public class TextVendingMachineInterface implements VendingMachineInterface { private VendingMachineController controller = new SimpleVendingMachineController(); private int selectedProduct; private CoinBundle change; @Override public void displayProducts() { System.out.println(" *********************************************"); System.out.println(" WELCOME TO THE VENDING MACHINE "); System.out.println(" *********************************************"); System.out.println(" Products available: "); System.out.println(" "); for(Product product: Product.values()){ if(!Product.EMPTY.equals(product)) { System.out.println(" " + product.getSelectionNumber() + " " + product.name() + " - Price: " + product.getPrice() + " "); } } System.out.println(" "); System.out.println(" Please select your product: "); } @Override public void selectProduct(int product) { this.selectedProduct = product; } @Override public void displayEnterCoinsMessage() { System.out.println(" Please enter coins as follows: "); System.out.println(" num of 5 cents coins,num of 10 cents coins,num of 20 cents coins,num of 50 cents coins,num of 100 cents coins "); System.out.println(" "); System.out.println(" Example: If you would like to enter 2 ten cents coins: 0,2,0,0,0"); System.out.println("Plese enter coins:"); } @Override public void enterCoins(int... coins) { VendingMachineRequest request = new VendingMachineRequest(selectedProduct, coins); change = controller.calculateChange(request); } @Override public void displayChangeMessage() { System.out.println(" "); System.out.println("Your change is :"+ change.getTotal()+"cents splitted as follows: "); System.out.println(" 100 cents coins: "+ change.number100CentsCoins); System.out.println(" 50 cents coins: "+ change.number50CentsCoins); System.out.println(" 20 cents coins: "+ change.number20CentsCoins); System.out.println(" 10 cents coins: "+ change.number10CentsCoins); System.out.println(" 5 cents coins: "+ change.number5CentsCoins); } }
Also, add this method to the CoinBundle
for the above code to work:
public int getTotal(){ int total = 0; total = total+this.number5CentsCoins*Coin.FIVE_CENTS.getValue(); total = total+this.number10CentsCoins*Coin.TEN_CENTS.getValue(); total = total+this.number20CentsCoins*Coin.TWENTY_CENTS.getValue(); total = total+this.number50CentsCoins*Coin.FIFTY_CENTS.getValue(); total = total+this.number100CentsCoins*Coin.HUNDRED_CENTS.getValue(); return total; }
Also, you will need to update the VendingMachineRequest
class and modify the constructor as follows:
public VendingMachineRequest(int selectedProduct,int... enteredCoins){ this.product = Product.valueOf(selectedProduct); this.enteredCoins = new CoinBundle(enteredCoins); }
And add a .valueOf()
method to the Product class. This method will map a number inserted by the user with an available product.
public static Product valueOf(int numberSelection){ for(Product product: Product.values()){ if(numberSelection == product.getSelectionNumber()){ return product; } } return EMPTY; }
VendingMachineController
Next, we will implement the VendingMachineController
interface by creating a class called SimpleVendingMachineController
. This class is merely coordinating communication between the previous interface and the calculator.
public class SimpleVendingMachineController implements VendingMachineController { private Calculator calculator = new SimpleCalculator(); @Override public CoinBundle calculateChange(VendingMachineRequest request) { int total = calculator.calculateTotal(request.enteredCoins); int totalChange = total - request.product.getPrice(); return calculator.calculateChange(totalChange); } }
Calculator
Next is the calculator which is the class that calculates the total amount inserted by the user. Furthermore it calculates the number of coins the user should receive. Therefore we will create a class called SimpleCalculator
, which will implement the Calculator
interface.
public class SimpleCalculator implements Calculator{ @Override public int calculateTotal(CoinBundle enteredCoins) { return enteredCoins.getTotal(); } @Override public CoinBundle calculateChange(int amountMoneyToReturn) { CoinBundle change = new CoinBundle(new int[5]); int remainingAmount = amountMoneyToReturn; change.number100CentsCoins = remainingAmount / Coin.HUNDRED_CENTS.getValue(); remainingAmount = remainingAmount % Coin.HUNDRED_CENTS.getValue(); change.number50CentsCoins = remainingAmount / Coin.FIFTY_CENTS.getValue(); remainingAmount = remainingAmount % Coin.FIFTY_CENTS.getValue(); change.number20CentsCoins = remainingAmount / Coin.TWENTY_CENTS.getValue(); remainingAmount = remainingAmount % Coin.TWENTY_CENTS.getValue(); change.number10CentsCoins = remainingAmount / Coin.TEN_CENTS.getValue(); remainingAmount = remainingAmount % Coin.TEN_CENTS.getValue(); change.number5CentsCoins = remainingAmount / Coin.FIVE_CENTS.getValue(); return change; } }
Main
classAnd finally, there is one small detail that we need to modify in the Main
class to complete the program implementation. After receiving the coins from the user as a String, we will need to convert them to an array of numbers. As a result, we will make the following change to the Main
class:
String userEnteredCoins = scanner.nextLine(); // this was : int[] enteredCoins = {} int[] enteredCoins = Coin.parseCoins(userEnteredCoins); machineInterface.enterCoins(enteredCoins);
And add the parseCoins()
method to the Coin
class:
public static int[] parseCoins(String coins){ String[] numberCoinsInText = coins.split(","); int[] result = new int[numberCoinsInText.length]; for(int index=0;index<numberCoinsInText.length;index++){ result[index] = Integer.parseInt(numberCoinsInText[index]); } return result; }
Perfect, you have completed your vending machine java program. You can test it by executing the Main
class.
In case you would like to create an executable file so you can share your new program with your friend, check this article where I explain how to package a java program.
All source code is available on Github
To summarize, this tutorial covers how to create a vending machine java program following an object-oriented programming approach. We went from defining requirements to create a skeleton implementation of our program and finally complete our vending machine java program.
I hope you enjoy the article and find it useful, and thank you so much for reading and supporting this blog!
Happy Coding!
Steady pace book with lots of worked examples. Starting with the basics, and moving to projects, data visualisation, and web applications
Unique lay-out and teaching programming style helping new concepts stick in your memory
Great guide for those who want to improve their skills when writing python code. Easy to understand. Many practical examples
Perfect Boook for anyone who has an alright knowledge of Java and wants to take it to the next level.
Excellent read for anyone who already know how to program and want to learn Best Practices
Perfect book for anyone transitioning into the mid/mid-senior developer level
Great book and probably the best way to practice for interview. Some really good information on how to perform an interview. Code Example in Java