Here’s a low-level design (LLD) for a Pizza Shop system in Java. This design includes key entities like Pizza
, Order
, Customer
, Payment
, and Toppings
, while ensuring modularity and flexibility using OOP principles such as inheritance and composition.
Key Components:
Pizza (Base Class & Variants)
Toppings (Decorator Pattern)
Order Management
Payment Handling
Customer & Store Management
1. Factory Pattern (For Creating Pizzas Dynamically)
Instead of manually instantiating pizzas, we use a Factory Pattern.
Pizza Factory Code
class PizzaFactory {
public static Pizza createPizza(String type) {
switch (type.toLowerCase()) {
case "margherita":
return new Margherita();
case "pepperoni":
return new Pepperoni();
default:
throw new IllegalArgumentException("Unknown Pizza Type: " + type);
}
}
}
Usage
Pizza pizza = PizzaFactory.createPizza("margherita");
2. Decorator Pattern (For Adding Toppings)
This pattern allows us to dynamically extend the Pizza
functionality.
Decorator Pattern Code
This was implemented in the original design:
abstract class ToppingDecorator extends Pizza {
protected Pizza pizza;
public ToppingDecorator(Pizza pizza) {
this.pizza = pizza;
}
public abstract String getDescription();
}
class Cheese extends ToppingDecorator {
public Cheese(Pizza pizza) {
super(pizza);
}
public String getDescription() {
return pizza.getDescription() + ", Cheese";
}
public double getCost() {
return pizza.getCost() + 1.50;
}
}
Usage
Pizza pizza = new Cheese(new Pepperoni()); // Pepperoni with extra cheese
3. Singleton Pattern (For Order Management)
We ensure a single instance of OrderManager
to manage all orders.
Singleton OrderManager
public class OrderManager {
private static volatile OrderManager instance;
private List<Order> orders;
private OrderManager() {
orders = new ArrayList<>();
}
public static OrderManager getInstance() {
if (instance == null) { // First check (without locking)
synchronized (OrderManager.class) {
if (instance == null) { // Second check (inside lock)
instance = new OrderManager();
}
}
}
return instance;
}
public void addOrder(Order order) {
orders.add(order);
System.out.println("Order added: " + order);
}
public List<Order> getOrders() {
return orders;
}
}
4. Strategy Pattern (For Payment Methods)
This pattern allows flexible payment method handling.
Payment Strategy Code
interface PaymentStrategy {
boolean pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
public boolean pay(double amount) {
System.out.println("Paid $" + amount + " via Credit Card: " + cardNumber);
return true;
}
}
class CashPayment implements PaymentStrategy {
public boolean pay(double amount) {
System.out.println("Paid $" + amount + " in Cash");
return true;
}
}
class PaymentProcessor {
private PaymentStrategy paymentStrategy;
public PaymentProcessor(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void processPayment(double amount) {
paymentStrategy.pay(amount);
}
}
Usage
PaymentProcessor paymentProcessor = new PaymentProcessor(new CreditCardPayment("1234-5678-9876-5432"));
paymentProcessor.processPayment(20.0);
5. Observer Pattern (For Order Status Notifications)
Used to notify customers when their order status changes.
Observer Pattern Code
import java.util.*;
interface Observer {
void update(String message);
}
class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
public void update(String message) {
System.out.println("Notification for " + name + ": " + message);
}
}
class OrderStatusNotifier {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
Usage
import java.util.*;
interface Observer {
void update(String message);
}
class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
public void update(String message) {
System.out.println("Notification for " + name + ": " + message);
}
}
class OrderStatusNotifier {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}