![]()
Java design patterns are proven solutions to common problems that developers face during software development. Below are the key design patterns that are frequently discussed in Java interviews:
1. Creational Design Patterns
These patterns deal with the process of object creation.
- Singleton Pattern: Ensures that a class has only one instance and provides a global point of access to it. Example:
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } - Factory Method Pattern: Provides an interface for creating objects, but allows subclasses to alter the type of objects that will be created. Example:
public abstract class Vehicle { public abstract void create(); } public class Car extends Vehicle { public void create() { System.out.println("Car Created"); } } public class VehicleFactory { public static Vehicle getVehicle(String type) { if (type.equalsIgnoreCase("Car")) { return new Car(); } return null; } } - Abstract Factory Pattern: Provides an interface for creating families of related or dependent objects without specifying their concrete classes. Example:
interface VehicleFactory { Vehicle createCar(); Vehicle createBike(); } class ConcreteFactory1 implements VehicleFactory { public Vehicle createCar() { return new Car(); } public Vehicle createBike() { return new Bike(); } } - Builder Pattern: Allows you to construct complex objects step by step, separating the construction process from the object representation. Example:
public class Vehicle { private String engine; private String wheels; public static class VehicleBuilder { private String engine; private String wheels; public VehicleBuilder setEngine(String engine) { this.engine = engine; return this; } public VehicleBuilder setWheels(String wheels) { this.wheels = wheels; return this; } public Vehicle build() { Vehicle vehicle = new Vehicle(); vehicle.engine = this.engine; vehicle.wheels = this.wheels; return vehicle; } } } - Prototype Pattern: Used when the creation of an object is costly or complex. The pattern involves cloning existing objects. Example:
public class Prototype implements Cloneable { private String type; public Prototype(String type) { this.type = type; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } }
2. Structural Design Patterns
These patterns focus on how classes and objects are composed to form larger structures.
- Adapter Pattern: Allows incompatible interfaces to work together by providing a wrapper that translates one interface to another. Example:
interface MediaPlayer { void play(String audioType, String fileName); } class AudioPlayer implements MediaPlayer { public void play(String audioType, String fileName) { System.out.println("Playing audio: " + fileName); } } class MediaAdapter implements MediaPlayer { private AudioPlayer audioPlayer; public MediaAdapter(AudioPlayer audioPlayer) { this.audioPlayer = audioPlayer; } public void play(String audioType, String fileName) { audioPlayer.play(audioType, fileName); } } - Facade Pattern: Provides a simplified interface to a complex subsystem, making it easier to use. Example:
public class CarEngine { public void start() { System.out.println("Engine started"); } } public class CarFacade { private CarEngine engine = new CarEngine(); public void startCar() { engine.start(); } } - Decorator Pattern: Adds additional functionality to an object dynamically without changing its structure. Example:
interface Car { void assemble(); } class BasicCar implements Car { public void assemble() { System.out.println("Basic Car."); } } class SportsCar implements Car { private Car car; public SportsCar(Car car) { this.car = car; } public void assemble() { car.assemble(); System.out.println("Adding features of Sports Car."); } } - Composite Pattern: Allows you to compose objects into tree-like structures and treat individual objects and compositions uniformly. Example:
interface Component { void showPrice(); } class Leaf implements Component { private int price; public Leaf(int price) { this.price = price; } public void showPrice() { System.out.println("Price: " + price); } } class Composite implements Component { private List<Component> components = new ArrayList<>(); public void addComponent(Component component) { components.add(component); } public void showPrice() { for (Component component : components) { component.showPrice(); } } }
3. Behavioral Design Patterns
These patterns focus on communication between objects.
- Strategy Pattern: Defines a family of algorithms and allows them to be interchangeable. The strategy pattern enables a class to change its behavior at runtime. Example:
interface Strategy { int doOperation(int num1, int num2); } class AddOperation implements Strategy { public int doOperation(int num1, int num2) { return num1 + num2; } } class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int executeStrategy(int num1, int num2) { return strategy.doOperation(num1, num2); } } - Observer Pattern: Allows one object (the subject) to notify a list of dependent objects (observers) about any state changes, typically used for implementing distributed event handling systems. Example:
interface Observer { void update(String message); } class ConcreteObserver implements Observer { public void update(String message) { System.out.println("Received message: " + message); } } class Subject { private List<Observer> observers = new ArrayList<>(); public void addObserver(Observer observer) { observers.add(observer); } public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } } - Command Pattern: Encapsulates a request as an object, thereby allowing for parameterization of clients with queues, requests, and operations. Example:
interface Command { void execute(); } class LightOnCommand implements Command { private Light light; public LightOnCommand(Light light) { this.light = light; } public void execute() { light.turnOn(); } } class Light { public void turnOn() { System.out.println("Light is ON"); } } - State Pattern: Allows an object to change its behavior when its internal state changes. The object will appear to change its class. Example:
interface State { void doAction(); } class StartState implements State { public void doAction() { System.out.println("Player is in start state."); } } class StopState implements State { public void doAction() { System.out.println("Player is in stop state."); } } class Context { private State state; public void setState(State state) { this.state = state; } public void executeAction() { state.doAction(); } }
