Let’s go over the main concepts we covered during this example project:
First, we modeled the products in the ProductDetail
class, and made it immutable by making the class and the attributes final, and not including any setter methods. In this way, the state of the instances couldn’t be modified after construction.
We created a ProductCatalog
interface that is the contract that separates the concerns of the vending machine from those of the specific implementation of the catalog. Then we implemented this interface in the InMemoryProductCatalog
class that stored the products in a HashSet
. This was made possible by overriding the equals
and hashCode
methods in the ProductDetail
class so they only depend on the productCode
, and thus preventing us from adding two products with the same code into the Set
.
The VendingMachine
class contains the business logic of the operation. It holds the current balance
and the maximum price for any item. It also receives the ProductCatalog
as an argument at construction, and throws an IllegalArgumentException
if the catalog is null
, empty, or any of its products exceeds the maximum allowed price.
For user interaction, we defined a Command Line Interface, or CLI
that receives a VendingMachine
to run and manages its interaction with the user.
It is modeled separately from the business logic of the VendingMachine
to facilitate possible changes in the user interface in the future (like adding a web interface for the vending machine). It uses a try/catch/finally
block to handle the possible InputMismatchException
that could be generated by an unexpected input from the Scanner
object.
And finally, we tested our program using a VendingMachineApp
with a HashSet
of dummy products in order to create an InMemoryProductCatalog
, a VendingMachine
, and a CLI
. And finally, it called the method on the CLI
class to run the vending machine and allow the user to enter commands and interact with the vending machine.