Java Object Oriented Analysis and Design Problem - Vending Machine Part 2

This is the second part of Java tutorial to show how to create Vending Machine in Java. In the first part, we have discussed problem statement and the solution itself, but unit testing and design document was still pending, which we'll see in this article.  As I said, there are multiple ways to implement Vending machine in Java e.g. you could have easily used state design pattern to implement a vending machine, in fact, it's one of the best examples of State design pattern. Vending machine behaves differently on different states e.g. return a product if the machine is not empty, otherwise, it just returns coins, so it ideally fits in state design pattern. Though, In our solution, I have not used the state design pattern but have just coded the solution with an if else block. This is easier because of a limited number of state and not many state transition but in more real world scenario, state design pattern is better as it uses Polymorphism and removes the logic we have put inside the if-else block.

Knowledge of UML is essential for creating a design document for Java programs. UML has several types of diagram to explain different aspect of your design e.g. class diagram to show the dependency of objects, sequence diagram to show how user will interact with your system and so on.

Since UML is a standard way to design Java application, it also works as shared library which many programmers understand. You don't need to explain that class A is related to class B, any Java programmer will figure out by himself by looking at the class diagram.

One book which has truly help me to understand UML better is UML for Java Programmers by Robert C. Martin. It's a great book if you want to learn UML from scratch or want to refresh your knowledge of UML. It also has similar exercises like designing a coffee machine in Java to test your object-oriented design and analysis skills.

Unit Test of Vending Machine Solution

Here is the unit test class for Vending Machine problem, which tests some behaviors of Vending machine e.g. buying items with exact change, with more change, less change, canceling an item, resetting vending machine etc. I admit that unit tests are not extensive enough and you can add few more test cases to fully test your vending machine solution in Java. Make sure to have your unit test in the same package but on the different root folder, so that you can test package private members without mixing production and testing code.


package vending;

import org.junit.Ignore;
import java.util.List;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.;

public class VendingMachineTest {
    private static VendingMachine vm;
    public static void setUp(){
        vm = VendingMachineFactory.createVendingMachine();
    public static void tearDown(){
        vm = null;
    public void testBuyItemWithExactPrice() {
        //select item, price in cents
        long price = vm.selectItemAndGetPrice(Item.COKE); 
        //price should be Coke's price      
        assertEquals(Item.COKE.getPrice(), price);
        //25 cents paid              
        Bucket<Item, List<Coin>> bucket = vm.collectItemAndChange();
        Item item = bucket.getFirst();
        List<Coin> change = bucket.getSecond();
        //should be Coke
        assertEquals(Item.COKE, item);
        //there should not be any change                              
    public void testBuyItemWithMorePrice(){
        long price = vm.selectItemAndGetPrice(Item.SODA);
        assertEquals(Item.SODA.getPrice(), price);
        Bucket<Item, List<Coin>> bucket = vm.collectItemAndChange();
        Item item = bucket.getFirst();
        List<Coin> change = bucket.getSecond();
        //should be Coke
        assertEquals(Item.SODA, item);
        //there should not be any change                                     
        //comparing change                             
        assertEquals(50 - Item.SODA.getPrice(), getTotal(change));  
    public void testRefund(){
        long price = vm.selectItemAndGetPrice(Item.PEPSI);
        assertEquals(Item.PEPSI.getPrice(), price);       
        assertEquals(41, getTotal(vm.refund()));       
    public void testSoldOut(){
        for (int i = 0; i < 5; i++) {
    public void testNotSufficientChangeException(){
        for (int i = 0; i < 5; i++) {
    public void testReset(){
        VendingMachine vmachine = VendingMachineFactory.createVendingMachine();
    public void testVendingMachineImpl(){
        VendingMachineImpl vm = new VendingMachineImpl();
    private long getTotal(List<Coin> change){
        long total = 0;
        for(Coin c : change){
            total = total + c.getDenomination();
        return total;

Design Document

Here is a sample design document for Vending Machine problem. Well, it's not that great but conveys my design decisions in text format. Since in a real test, time is critical you need to balance your time between coding, testing, and designing activity, it's better to choose text over an image. If you are good with UML than adding a class diagram would certainly help here.

In Short Design Document in Java Should include
- description of the solution
- design decision and data structures
- All classes and there responsibility
- description of the package
- description of methods
- the motivation of decision e.g. why this design pattern, why enum, why BigDecimal etc?
- Flow Chart of couple of use cases
- UML Diagram
- Assumption
- Risk
- Benefits

Here is our sample design document, it's very basic because I have generated it very quickly, but it's good for learning and doing Object Oriented Analysis and design. One thing which I would like to add on this document is UML class diagram because that's another way to convey your design to fellow Java developers. I have  added it to this discussion. If you want to learn UML then don't forget to check out UML for Java Programmers by Robert C. Martin

Java Object Oriented Analysis and Design Problem - Vending Machine Part 2

1) High-level Design

Includes overview of the problem, not necessary if you are writing this as part of the test because evaluator should be familiar with problem specification. Important if your design document is intended for someone who is not very familiar with the problem domain.

    - Main interface, classes and Exceptions
          - VendingMachine - an interface which defines public API of VendingMachine
          - VendingMachineImpl - a general purpose implementation of VendingMachine interface
          - Inventory - A type-safe inventory for holding objects, which is an ADAPTER or WRAPPER over java.util.Map
          - Item - type-safe Enum to represent items supported by vending machine.
          - Coin - type-safe Enum to represent coins, which is acceptable by vending machine.
          - Bucket - A Holder class for holding two types together.
          - SoldOutException - thrown when user selects a product which is sold out
          - NotSufficientChangeException - thrown when Vending machine doesn't have enough change to support the current transaction.

          - NotFullPaidException - thrown when the user tries to collect an item, without paying the full amount.
    - Data structures used
          - Map data structure is used to implement cash and item inventories.
          - The List is used to returning changes because it can contain duplicates, i.e. multiple coins of the same denomination.

    - Motivation behind design decisions
         - Factory design pattern is used to encapsulate creation logic of VendingMachine.
         - Adapter pattern is used to create Inventory by wrapping java.util.Map
         - java.lang.Enum is used to represent Item and Coins, because of following benefits
                - compile time safety against entering an invalid item and invalid coin.
                - no need to write code for checking if selected item or entered coin is valid.
                - reusable and well encapsulated.
         - long is used to represent price and totalSales, which are the amount because we are dealing in cents.
           Not used BigDecimal to represent money, because the vending machine can only hold limited amount, due to finite capacity of coin inventory.


2) Low Leven Design

    - Methods
        -  The getChange() method uses a greedy algorithm to find out whether we have sufficient coins to support an amount.

    - Initialization
         - When Vending Machine will be created, it's initialized with default cash and item inventory. current with quantity 5 for each coin and item.

2) Testing Strategy
   - Three primary test cases to testWithExactPrice()testWithMorePrice() and testRefund() to cover general usecase.
   - Negative test cases like testing SoldOutExceptionNotSufficientChangeException or NotFullPaidException

3) Benefits
   - The design uses Abstraction to create reusable, small classes which are easier to read and test.
   - Encapsulating Items and Coins on their respective class makes it easy to add new Coins and Items.
   - Inventory is general purpose class and can be used elsewhere, It also encapsulates all inventory operations.

4) Assumption
   - Vending Machine is single-threaded, only one user will operate at a time.
   - A call to reset() will reset item and balance i.e. make them zero.

UML Diagram Vending Machine in Java

Here is our UML diagram for this solution, generated in Eclipse by using ObjectAid plugin. It let you create UML class diagram from Java code itself. This diagram shows that VendingMachineImpl extends or implements VendingMachine interface. It also shows that it is associated with Item and Inventory classes.

If you are new in Java and not understanding this UML diagram then you should  read UML for Java Programmers by Robert C. Martin , one of the best books to learn about UML and class diagram of  Java programs.

Vending Machine in Java coding, design and UML

That's all on this two-part article on designing and implementing Vending Machine in Java using Object Oriented analysis and design. If you have just started learning OOPS or Java, I recommend doing this kind of design related exercise to improve your design skills in Java. You will face a lot of challenges, which will drive further learning and understanding of core OOPS concept. If you are hungry for more of such design problems in Java, you should read  UML for Java Programmers by Robert C. Martin to practice another similar problem of designing a coffee machine in Java. Uncle Bob has explained much better than me, so there is good chance that you will learn something there as well.


Ashkrit said...

On such type of questions what are your thoughts on implementations
- code solution and then test
- or TDD way

What do company look for ?

Javin Paul said...

Hello @Ashkrit, good question. IMHO, what matter most is the correct solution within the timeframe. If you feel you are more comfortable with TDD, go with that but if you are not someone who use TDD daily then go with traditional approach of plan + code + Test. Company look for correct solution, if they get more than one correct solution obviously they will select the code which is more maintainable, flexible and clean. It's not worth to leave the problem in half because you don't have enough time.

Post a Comment