1. Builder Pattern
Use Case:
To create complex objects (e.g., Order
) with multiple optional parameters without writing large constructors.
Explanation:
In a food delivery app, an order can have various attributes like customer details, items, payment methods, etc. The Builder Pattern
allows creating an object step-by-step, ensuring readability and flexibility.
// Builder Pattern
class Order {
private String customerName;
private String address;
private List<String> items;
private String paymentMethod;
private Order(OrderBuilder builder) {
this.customerName = builder.customerName;
this.address = builder.address;
this.items = builder.items;
this.paymentMethod = builder.paymentMethod;
}
public static class OrderBuilder {
private String customerName;
private String address;
private List<String> items = new ArrayList<>();
private String paymentMethod;
public OrderBuilder setCustomerName(String customerName) {
this.customerName = customerName;
return this;
}
public OrderBuilder setAddress(String address) {
this.address = address;
return this;
}
public OrderBuilder addItem(String item) {
this.items.add(item);
return this;
}
public OrderBuilder setPaymentMethod(String paymentMethod) {
this.paymentMethod = paymentMethod;
return this;
}
public Order build() {
return new Order(this);
}
}
}
// Usage
public class BuilderExample {
public static void main(String[] args) {
Order order = new Order.OrderBuilder()
.setCustomerName("John Doe")
.setAddress("123 Main St")
.addItem("Pizza")
.addItem("Soda")
.setPaymentMethod("Credit Card")
.build();
System.out.println("Order successfully placed.");
}
}
2. Factory Pattern
Use Case:
To dynamically create objects like delivery types (bike, car, drone).
Explanation:
The Factory Pattern
is ideal for instantiating different delivery modes based on the context without exposing the instantiation logic to the client.
// Factory Pattern
interface DeliveryPartner {
void deliver();
}
class BikeDelivery implements DeliveryPartner {
@Override
public void deliver() {
System.out.println("Delivering by bike.");
}
}
class CarDelivery implements DeliveryPartner {
@Override
public void deliver() {
System.out.println("Delivering by car.");
}
}
class DroneDelivery implements DeliveryPartner {
@Override
public void deliver() {
System.out.println("Delivering by drone.");
}
}
class DeliveryPartnerFactory {
public static DeliveryPartner getDeliveryPartner(String type) {
switch (type.toLowerCase()) {
case "bike":
return new BikeDelivery();
case "car":
return new CarDelivery();
case "drone":
return new DroneDelivery();
default:
throw new IllegalArgumentException("Unknown delivery type: " + type);
}
}
}
// Usage
public class FactoryExample {
public static void main(String[] args) {
DeliveryPartner partner = DeliveryPartnerFactory.getDeliveryPartner("bike");
partner.deliver(); // Output: Delivering by bike.
}
}
3. Observer Pattern
Use Case:
To notify customers about order status updates in real time.
Explanation:
The Observer Pattern
allows multiple subscribers (e.g., customers) to receive updates from a subject (e.g., order delivery system). It's perfect for real-time notification systems.
// Observer Pattern
interface Observer {
void update(String status);
}
class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
@Override
public void update(String status) {
System.out.println(name + " received update: " + status);
}
}
class OrderService {
private List<Observer> observers = new ArrayList<>();
private String orderStatus;
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void setOrderStatus(String status) {
this.orderStatus = status;
notifyObservers();
}
private void notifyObservers() {
for (Observer observer : observers) {
observer.update(orderStatus);
}
}
}
// Usage
public class ObserverExample {
public static void main(String[] args) {
OrderService orderService = new OrderService();
Observer customer1 = new Customer("Alice");
Observer customer2 = new Customer("Bob");
orderService.addObserver(customer1);
orderService.addObserver(customer2);
orderService.setOrderStatus("Order is being prepared.");
orderService.setOrderStatus("Order is out for delivery.");
}
}
4. Singleton Pattern
Use Case:
To ensure a single instance of a configuration manager for global settings.
Explanation:
The Singleton Pattern
is used to manage global states like app configurations, database connections, or logging in food delivery systems.
// Singleton Pattern
class ConfigManager {
private static ConfigManager instance;
private String config;
private ConfigManager() {
config = "Default Configuration";
}
public static synchronized ConfigManager getInstance() {
if (instance == null) {
instance = new ConfigManager();
}
return instance;
}
public String getConfig() {
return config;
}
public void setConfig(String config) {
this.config = config;
}
}
// Usage
public class SingletonExample {
public static void main(String[] args) {
ConfigManager config1 = ConfigManager.getInstance();
ConfigManager config2 = ConfigManager.getInstance();
config1.setConfig("New Configuration");
System.out.println(config1.getConfig()); // Output: New Configuration
System.out.println(config2.getConfig()); // Output: New Configuration
}
}
5. Strategy Pattern
Use Case:
To handle different payment strategies (e.g., credit card, PayPal).
Explanation:
The Strategy Pattern
allows swapping payment methods dynamically without modifying the client code.
// Strategy Pattern
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " using Credit Card.");
}
}
class PayPalPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " using PayPal.");
}
}
class PaymentContext {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void pay(double amount) {
strategy.pay(amount);
}
}
// Usage
public class StrategyExample {
public static void main(String[] args) {
PaymentContext context = new PaymentContext();
context.setPaymentStrategy(new CreditCardPayment());
context.pay(50.0); // Output: Paid $50.0 using Credit Card.
context.setPaymentStrategy(new PayPalPayment());
context.pay(75.0); // Output: Paid $75.0 using PayPal.
}
}