Determine the different ways the system will be used. This includes main functions the system needs to perform and who will use it.
1) The system should manage the stock of items available in the vending machine, including keeping track of quantities and updating them when items are purchased.
2) The vending machine should accept multiple payment methods, including:
3) The system should alert operators when maintenance is needed, such as low inventory or malfunctioning payment systems.
4) The vending machine should be able to dispense the correct items based on user selection and ensure that items are available before confirming a purchase.
Based on the requirements and use cases, identify the main objects of the system...
An abstract Item class with fields like itemCount, costOfSingleItem, and description. Subclasses such as FoodItem and SoftDrink will extend this class, updating fields like itemCount and price accordingly.
A PaymentStrategy interface that defines different payment strategies. Implementations will include strategies like PayByCashStrategy, PayByCoinsStrategy, and CreditCardStrategy.
A User class containing fields like name, surname, and mobileNumber. It will be extended by Customer and HelpDesk classes. The observer pattern will be used to notify the helpdesk in case of payment failures or issues adding items to the cart.
A Cart class that will store all the items and calculate the total amount of those items.
Determine how these objects will interact with each other to fulfill the use cases...
Each User has one or more than 1 cart . Each Cart we store will store 1 or more items and based and there will be foodItem, SoftDrink Item which will extend the Item class also the cart will have the payment strategy to store the payment strategy used by the user like pay by coins
Design inheritance trees where applicable to promote code reuse and polymorphism. This step involves identifying common attributes and behaviors that can be abstracted into parent classes...
Each User has one or more than 1 cart . Each Cart we store will store 1 or more items and based and there will be foodItem, SoftDrink Item which will extend the Item class also the cart will have the payment strategy to store the payment strategy used by the user like pay by coins
Consider using design patterns (e.g., Factory, Singleton, Observer, Strategy) that fit the problem...
Factory Pattern - > we are using factory pattern to create different classes for item.
Strategy Patter -> For implementing different payment methods we will be using strategy pattern.
Observer pattern- > For notifying the helpdesk in case of any payment failure or other issues.
Attributes: For each class, define the attributes (data) it will hold...
Methods: Define the methods (functions) that operate on the attributes. Ensure they align with the object's responsibilities and adhere to the principle of encapsulation.
import java.util.List;
abstract class Item {
protected int itemCount;
protected double costOfSingleItem;
protected String description;
public Item(int itemCount, double costOfSingleItem, String description) {
this.itemCount = itemCount;
this.costOfSingleItem = costOfSingleItem;
this.description = description;
}
public abstract double calculateTotalCost();
}
class FoodItem extends Item {
public FoodItem(int itemCount, double costOfSingleItem, String description) {
super(itemCount, costOfSingleItem, description);
}
@Override
public double calculateTotalCost() {
return itemCount * costOfSingleItem;
}
}
class SoftDrink extends Item {
public SoftDrink(int itemCount, double costOfSingleItem, String description) {
super(itemCount, costOfSingleItem, description);
}
@Override
public double calculateTotalCost() {
return itemCount * costOfSingleItem;
}
}
interface PaymentStrategy {
void pay(double amount);
}
class PayByCashStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid by cash: " + amount);
}
}
class PayByCoinsStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid by coins: " + amount);
}
}
class CreditCardStrategy implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid by credit card: " + amount);
}
}
abstract class User {
protected String name;
protected String surName;
protected String mobileNumber;
public User(String name, String surName, String mobileNumber) {
this.name = name;
this.surName = surName;
this.mobileNumber = mobileNumber;
}
public abstract void notify(String message);
}
class Customer extends User {
public Customer(String name, String surName, String mobileNumber) {
super(name, surName, mobileNumber);
}
@Override
public void notify(String message) {
System.out.println("Customer Notification: " + message);
}
}
class HelpDesk extends User {
public HelpDesk(String name, String surName, String mobileNumber) {
super(name, surName, mobileNumber);
}
@Override
public void notify(String message) {
System.out.println("HelpDesk Notification: " + message);
}
}
class Cart {
private List<Item> items;
private double totalAmount;
public Cart() {
this.items = new ArrayList<>();
this.totalAmount = 0.0;
}
public void addItem(Item item) {
items.add(item);
totalAmount += item.calculateTotalCost();
}
public double getTotalAmount() {
return totalAmount;
}
public void checkout(PaymentStrategy paymentStrategy) {
paymentStrategy.pay(totalAmount);
}
}
Check and explain whether your design adheres to solid principles (Ask interviewer what SOLID principle is if you can not recall it.)...
Single Responsibility Principle (SRP): Each class in the implementation has a single responsibility. The Item hierarchy handles item-specific behavior, PaymentStrategy implementations handle different payment methods, User hierarchy manages user-related details and notifications, and Cart manages the items and the total cost.
Open/Closed Principle (OCP): Classes are open for extension but closed for modification. For example, if we want to add a new item type or payment strategy, we can extend the Item class or implement a new PaymentStrategy without modifying existing code.
Liskov Substitution Principle (LSP): The subclasses in the Item and User hierarchies can be used in place of their parent classes without altering the behavior of the program. For example, any Item subclass can be added to the Cart without changing how the total cost is calculated.
Interface Segregation Principle (ISP): The PaymentStrategy interface is small and focused on a single responsibility (making a payment), so clients are not forced to implement methods they don't need.
Dependency Inversion Principle (DIP): High-level modules like Cart do not depend on low-level modules; instead, they depend on abstractions (PaymentStrategy). This makes the system more flexible and easier to modify or extend.
Explain how your design can handle changes in scale and whether it would be easily to extend with new functionalities...
For adding new Payment strategy we can extend the payment strategy and add new payment strategies. For adding new item we can extend the item class adding item is also very flexible
Try creating a class, flow, state and/or sequence diagram using the diagramming tool. Mermaid flow diagrams can be used to represent system use cases. You can ask the interviewer bot to create a starter diagram if unfamiliar with the tool. Briefly explain your diagrams if necessary...
Added class Diagram
Critically examine your design for any flaws or areas for future improvement...