This repository demonstrates classical object-oriented design patterns grouped in:
CreationalpatternsStructuralpatternsBehaviouralpatterns
Each section now includes:
- pattern definition
- ideal code structure and class relationships
- repository implementation details
Creational patterns control object creation, making software resilient to direct dependencies and configuration changes.
Definition:
- Ensures one and only one instance of a class exists.
- Provides a global point of access (often static method
getInstance()).
Ideal Structure:
class Singletonwith private constructor.private static Singleton instancefield.public static synchronized Singleton getInstance()returns existing instance or creates.
Pseudo:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
public void doWork() {}
}
Implementation details:
MySingleton.java: implements Bill Pugh Singleton pattern for thread-safety without synchronization overhead. Includes commented alternatives (synchronized method, double-checked locking).Driver.java: callsMySingleton.getInstance()multiple times and verifies object identity.
This pattern demonstrates a centralized shared service object, similar to a logging singleton in applications.
Definition:
- Encapsulate object creation behind a factory.
- Clients ask factory for interface, not concrete classes.
Ideal Structure:
Productinterface or abstract class.- Concrete product classes implement
Product. - Factory class has a method
createProduct(type).
Pseudo:
interface Pizza { void prepare(); }
class Margherita implements Pizza { ... }
class Pepperoni implements Pizza { ... }
class PizzaFactory {
static Pizza createPizza(PizzaType type) {
switch(type) { ... }
}
}
Implementation details:
Pizza.java: base contractprepare()andgetName().PizzaType.java: enum for type decisions.PizzaFactory.java: modern switch expression for clean, readable type selection.- Driver: selects a type and prints result.
This pattern demonstrates how a central factory can select and instantiate pizza types at runtime with minimal client modification.
Definition:
- Creates families of related products without specifying concrete classes.
- Each factory is per family (dominos vs PizzaHut) and produces same product family variants.
Ideal Structure:
AbstractFactorydefines methods likecreateChickenPizza(),createTomatoPizza().- Concrete factories implement these for brand-specific variants.
- Client uses
AbstractFactoryplusStoreTyperoute.
Pseudo:
interface AbstractPizzaFactory { Pizza createPizza(PizzaType); }
class DominosFactory implements AbstractPizzaFactory { ... }
class PizzaHutFactory implements AbstractPizzaFactory { ... }
Implementation details:
AbstractPizzaFactory.java: factory interface, possiblygetPizza(PizzaType).AbstractPizzaFactory.java(client/director) chooses store byStoreTypeand requests pizza.StoreType.java: enum to pick factory.DominosPizzaFactoryandPizzaHutPizzaFactory: returns brand-specificChickenPizza,OnionPizza,TomatoPizza.
This pattern demonstrates selecting consistent product kinds from different vendors via a unified abstract factory interface.
Definition:
- Constructs complex object step by step.
- Permits immutability and readable code when optional parameters exist.
Ideal Structure:
Product(e.g., query object) with many fields.Builderwith setter methods returningthis.build()returns final product.
Pseudo:
class Query { ... }
class QueryBuilder {
QueryBuilder select(String... cols) { ...; return this; }
QueryBuilder from(String table) { ...; return this; }
Query build() { return new Query(...); }
}
Implementation details:
Query.java: hold final SQL string or query properties.QueryBuilder.java: methodsselect(),from(),where(),groupBy(),orderBy(),build().Driver.java: demonstrates fluent API withnew QueryBuilder().select(...)...build().
This pattern demonstrates building complex SQL queries safely through a fluent builder API.
Structural patterns organize class and object composition for maintainable subsystems.
Definition:
- Convert one interface to another expected by clients.
- Wrap incompatible class with adapter.
Ideal Structure:
- Client expects
Targetinterface. - Available class has
Adapteeinterface. AdapterimplementsTarget, holdsAdaptee, translates calls.
Pseudo:
interface Payment { void pay(amount); }
class RazorPay { void makePayment(amountInCents); }
class RazorPayAdapter implements Payment {
RazorPay razor;
pay(amount) { razor.makePayment(amount*100); }
}
Implementation details:
- Legacy path and modern path both show adapter technique.
PaymentProcessorusesAdapterPaymentinterchangeably with underlying gateway impl.Driverdemonstrates both Stripe and RazorPay through common interface.
This pattern demonstrates integrating multiple payment providers with one adapter interface, avoiding business logic changes.
Definition:
- Attach responsibilities to objects at runtime.
- Decorators follow same interface as base component.
Ideal Structure:
Componentinterface (Burger).- Concrete
Component(VegBurger,ChickenBurger). - Abstract decorator class (
BurgerDecorator) implements component and holdsComponent. - Concrete decorators (
ExtraCheese,ExtraPatty) add behavior.
Pseudo:
Burger burger = new ExtraCheese(new ExtraPatty(new VegBurger()));
burger.describe();
Implementation details:
- Base ingredients and price are extended in decorators using composition.
- Output includes accumulated price and features.
Driverdemonstrates chaining multiple decorators.
This pattern demonstrates extending orders dynamically with decorators so new combinations do not require subclass explosion.
Definition:
- Provide simplified interface over complex subsystem.
- Clients call one entrypoint, not multiple subsystem methods.
Ideal Structure:
- Subsystem classes (
VegMenu,NonVegMenu,JuiceMenu) with detailed methods. MenuManagerfacade aggregates and hides complexity.- Client calls
MenuManager.showMenu().
Implementation details:
- Menu facade:
src/Structural/Facade/MenuLists/MenuManager.javahas methods likedisplayFullMenu(),showVeg(),showNonVeg(). Subsystem details are abstracted inServices/classes. - API Gateway facade:
src/Structural/Facade/ApiGateWay/ApiGateWay.javaorchestrates order placement withUserService,OrderService,PaymentService,NotificationService,DeliveryService. - Drivers:
MenuLists/Driver.javauses facade for one-step menus;ApiGateWay/Driver.javademonstrates simplified order placement.
This pattern demonstrates simplifying menu access via a facade to shield frontend from subsystem complexity, and also shows an API gateway facade for payment and order processing.
Behavioural patterns manage algorithms and object interactions.
Definition:
- Define interchangeable algorithms via strategy interface.
- Context uses strategy by composition.
Ideal Structure:
Strategyinterface withexecute().- Concrete strategies implement variant algorithms.
Contextholds Strategy and callsstrategy.execute().
Pseudo:
class PaymentContext { setStrategy(PaymentStrategy s); pay(amount) { s.pay(amount); }}
Implementation details:
PaymentStrategyinterface withpay(int amount).- Implementations:
CreditCardPayment,PaypalPayment,UpiPayment. PaymentContextis configured at runtime with selected strategy.Drivershows switching at runtime.
This pattern demonstrates dynamic strategy selection for payment methods, centralizing choice in the context.
Definition:
- One subject notifies many observers on state changes.
- Observers subscribe/unsubscribe from subject.
Ideal Structure:
Subjectinterface holds observers and notifies.ConcreteSubjecttracks state and notifies changes.Observerinterface definesupdate().ConcreteObserversreact to updates.
Pseudo:
subject.attach(new ScoreObserver());
subject.setEvent(event);
subject.notifyObservers();
Implementation details:
BowlingEventstores match state (runs, wicket, overs).ScoreBoard(subject) sets events and triggersupdate()on observer list.OverObserver,ScoreObserver,WicketObserverdisplay slices.Driversimulates event push and observer update with cricket scoring events.
This pattern demonstrates a subject notifying multiple observers for real-time score updates.
Definition:
- Allows an object to change its behavior when its internal state changes.
- Encapsulates state-specific behavior into separate classes (states), and the context delegates requests to the current state.
Ideal Structure:
Context(e.g.,VendingMachine) holds a reference to aState.Stateinterface defines operations (e.g.,selectItem(),insertMoney(),dispense(),cancel()).- Concrete state classes implement the operations and can transition the context to another state.
Repository Implementation details:
src/Behavioural/State/VendingMachine.java: context that delegates actions toMachineState.src/Behavioural/State/VendingMachineStates/MachineState.java: state interface.- Concrete states:
IdleState→ initial stateSelectedState→ after item selectionPaymentDoneState→ after payment
- Transitions happen inside state classes using
machine.setState(new NextState()).
Sample flow (from src/Behavioural/State/Driver.java):
package Behavioural.State;
public class Driver {
public static void main(String[] args){
System.out.println("\n Vending Machine using State Pattern \n");
VendingMachine machine = new VendingMachine();
// invalid operations in Idle
machine.insertMoney();
machine.dispense();
System.out.println("--------------------------");
// select -> pay -> dispense
machine.selectItem();
machine.insertMoney();
machine.dispense();
System.out.println("--------------------------------");
// cancel flow
machine.selectItem();
machine.cancel();
}
}Sample output:
Vending Machine using State Pattern
Select Item First
No Item Selected
--------------------------
Item Selected
Amount has been Paid
Item is ready to dispense
--------------------------------
Item Selected
Product cancelled
This pattern demonstrates how conditional logic like if(state==...) can be replaced with polymorphism and state-driven transitions.
- Navigate to repository root:
cd /home/prakashkalari/Documents/ME/java/DesignPatterns - Compile all sources:
rm -rf out && mkdir -p out javac -d out $(find src -name '*.java')
- Run each driver, for example:
java -cp out Creational.Singleton.Driver java -cp out Creational.Factory.Driver java -cp out Creational.AbstractFactory.Driver java -cp out Creational.Builder.Driver java -cp out Structural.Adapter.LegacyCode.Driver java -cp out Structural.Adapter.PaymentGateway.Driver java -cp out Structural.Decorator.Driver java -cp out Structural.Facade.MenuLists.Driver java -cp out Structural.Facade.ApiGateWay.Driver java -cp out Behavioural.Observer.Driver java -cp out Behavioural.Strategy.GPS.Driver java -cp out Behavioural.Strategy.PaymentMode.Driver java -cp out Behavioural.State.Driver
- Start with
Creational/Singletonfor global-object concept. - Learn
Factoryto decouple client from concrete types. - Compare with
AbstractFactoryfor product families. - Then
Builderfor complex construction. - Move to
Structural(Adapter,Decorator,Facade) to understand class composition and wrappers. - Finish with
Behavioural(Strategy,Observer) for runtime behavior change and communication.
- This set is intentionally limited and easy to read for newcomers.
- Recommended next patterns in same structure:
Command,TemplateMethod,Composite,Proxy,Mediator. - Reference books: "Head First Design Patterns" and "Design Patterns: Elements of Reusable Object-Oriented Software" (Gamma et al.).
- Code uses modern Java features like switch expressions and Bill Pugh Singleton for best practices.