Java Design Patterns for Interviews

Loading

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(); } }

Leave a Reply

Your email address will not be published. Required fields are marked *