Bird
Raised Fist0

SOLID Principles - Single Responsibility to Dependency Inversion with Real Code

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
AbstractBaseClass and SingleResponsibilityClass inheritance

AbstractBaseClass is an abstract class holding shared state and templateMethod, which SingleResponsibilityClass extends to add specific behavior.

🎯 Tests whether candidate knows abstract class is used because it holds instance state shared by subclasses, which interfaces cannot hold in Java.
public abstract class AbstractBaseClass {
    protected String sharedState;
    public final void templateMethod() {
        commonStep();
        abstractStep();
    }
    private void commonStep() {
        System.out.println("Common step with " + sharedState);
    }
    protected abstract void abstractStep();
}
SingleResponsibilityClass concrete implementation

SingleResponsibilityClass extends AbstractBaseClass and implements abstractStep with specific logic, enforcing Single Responsibility Principle.

🎯 Tests if candidate understands Template Method pattern usage and that subclass adds specific behavior without modifying base class, adhering to OCP.
public class SingleResponsibilityClass extends AbstractBaseClass {
    private int specificState;
    @Override
    protected void abstractStep() {
        System.out.println("Specific step with " + specificState);
    }
    public void doSpecificTask() {
        templateMethod();
    }
}
DependencyInterface and ConcreteDependency realization

DependencyInterface defines performAction method; ConcreteDependency implements it, enabling Dependency Inversion Principle by coding to interface.

🎯 Tests if candidate knows interface is used to abstract dependency behavior, allowing flexible substitution and adherence to DIP.
public interface DependencyInterface {
    void performAction();
}
public class ConcreteDependency implements DependencyInterface {
    @Override
    public void performAction() {
        System.out.println("ConcreteDependency action performed");
    }
}
ClientClass composition and dependency injection

ClientClass composes DependencyInterface and receives it via constructor injection, demonstrating composition lifecycle and Dependency Injection pattern.

🎯 Tests if candidate understands composition lifecycle (ClientClass owns dependency reference but not lifecycle) and constructor injection to decouple dependencies.
public class ClientClass {
    private final DependencyInterface dep;
    public ClientClass(DependencyInterface dep) {
        this.dep = dep;
    }
    public void execute() {
        dep.performAction();
    }
}
📐
Class Diagram
Class Diagram
       +-------------------------+
       | <<Abstract>>            |
       | AbstractBaseClass       |
       |-------------------------|
       | - sharedState: String   |
       |-------------------------|
       | + templateMethod():void |
       | + abstractStep():void   |
       +-------------------------+
                 │ extends
       +-------------------------+
       | SingleRespClass         |
       |-------------------------|
       | - specificState: int    |
       |-------------------------|
       | + doSpecificTask():void |
       +-------------------------+
       
       +-------------------------+
       | <<Interface>>           |
       | DependencyInterface     |
       |-------------------------|
       | + performAction():void  |
       +-------------------------+
                 ─ ─ ─► realization
       +-------------------------+
       | ConcreteDependency      |
       |-------------------------|
       | + performAction():void  |
       +-------------------------+
       
       +-------------------------+
       | ClientClass             |
       |-------------------------|
       | - dep: DependencyInterface |
       |-------------------------|
       | + ClientClass(dep):void  |
       | + execute():void        |
       +-------------------------+
                 ◆ composition

This diagram illustrates key SOLID principles in Java with real code. AbstractBaseClass is an abstract class holding shared state and a template method, showing why abstract classes are chosen over interfaces when state is needed. SingleResponsibilityClass extends it, implementing specific behavior, demonstrating the Template Method pattern and Single Responsibility Principle. DependencyInterface is a pure interface defining a contract, realized by ConcreteDependency, enforcing Dependency Inversion Principle by coding to abstractions. ClientClass composes DependencyInterface and uses constructor-based Dependency Injection, showing composition lifecycle ownership and decoupling dependencies. These design decisions ensure extensibility, maintainability, and clear lifecycle management in Java.

Primary Focus

✓ Abstract class vs Interface state + Dependency Injection OCP + Composition lifecycle + Template Method pattern

Practice

(1/5)
1. A class Facade provides a simplified interface to a complex subsystem by delegating calls to multiple internal classes. It hides subsystem details from clients. Which design pattern is this an example of, and why is it the correct choice here?
easy
A. Facade pattern, because it provides a unified interface to a set of interfaces in a subsystem.
B. Proxy pattern, because it controls access to the subsystem objects.
C. Adapter pattern, because it converts one interface to another expected by clients.
D. Decorator pattern, because it adds responsibilities dynamically to objects.

Solution

  1. Step 1: Identify the role of the Facade class

    The Facade class simplifies client interaction by exposing a single interface that delegates to multiple subsystem classes, hiding complexity.
  2. Step 2: Differentiate from similar patterns

    Decorator adds behavior dynamically, Adapter changes interface, Proxy controls access; none simplify multiple interfaces into one.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Facade unifies subsystem interfaces -> simplified client interaction [check]
Hint: Facade unifies interfaces, Adapter converts, Decorator adds behavior [check]
Common Mistakes:
2. A class provides a createIterator() method that returns an object allowing traversal over its elements without exposing its internal data structure. Which design pattern is being applied and why is this the correct choice?
easy
A. Factory Method pattern, because it encapsulates object creation logic.
B. Decorator pattern, because it adds traversal behavior dynamically.
C. Iterator pattern, because it separates traversal logic from the collection's internal structure.
D. Composite pattern, because it treats individual and composite objects uniformly.

Solution

  1. Step 1: Identify the role of createIterator()

    This method returns an object that allows clients to traverse elements without exposing the collection's internal representation, which is the core intent of the Iterator pattern.
  2. Step 2: Eliminate other patterns

    Factory Method focuses on object creation, Decorator adds responsibilities dynamically, and Composite manages tree structures. None focus on traversal abstraction.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Iterator separates traversal from collection internals [check]
Hint: Iterator hides structure, exposes traversal [check]
Common Mistakes:
3. In a multiplayer card game, the Hand class has a method addCard(Card card) that is not synchronized. Two threads concurrently add cards to the same hand. Which exact sequence causes a race condition leading to lost cards?
medium
A. Thread 1 reads current card list size -> context switch -> Thread 2 reads same size -> both add at same index, overwriting one card.
B. Thread 1 locks hand, adds card, unlocks; Thread 2 waits and then adds card safely.
C. Thread 1 and Thread 2 both add cards simultaneously without any interleaving.
D. Thread 1 and Thread 2 both call addCard but cards are queued and processed sequentially.

Solution

  1. Step 1: Identify the check-then-act gap

    Without synchronization, both threads read the current size of the card list before either adds their card.
  2. Step 2: Trace interleaving causing overwrite

    Thread 1 reads size N, context switches; Thread 2 reads size N; both add at index N, causing one card to overwrite the other.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized addCard -> check-then-act race -> lost card [check]
Hint: Check size -> context switch -> duplicate index add -> lost card [check]
Common Mistakes:
4. In the Jigsaw Puzzle System, the Board class has a placePiece() method that first checks if a position is free and then places the piece. Without synchronizing placePiece(), what exact sequence of thread interleaving causes two threads to place different pieces at the same position (double-booking)?
medium
A. Thread 1 checks position free -> true, context switch; Thread 2 checks position free -> true; both place pieces concurrently.
B. Thread 1 places piece, Thread 2 waits, then places piece after Thread 1 finishes.
C. Thread 1 and Thread 2 both call placePiece() but on different board instances, causing no conflict.
D. Thread 1 locks the board, Thread 2 spins waiting, so no double-booking occurs.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, Thread 1 checks position free and sees true, but before placing, context switches.
  2. Step 2: Thread 2 also checks position free -> true and proceeds to place piece concurrently, causing double-booking.

  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act allows both threads to place pieces at same position [check]
Hint: Check-then-act without sync -> double-booking race [check]
Common Mistakes:
5. To add support for ElectricCar and ChargingSpot in the Chess game parking lot design, what is the minimum change that respects extensibility without modifying existing classes?
hard
A. Create new ElectricCar and ChargingSpot classes and modify ParkingLot to handle them explicitly.
B. Modify VehicleType and SpotType enums to include electric types and add compatibility logic inside existing classes.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
D. Add a boolean isElectric flag to Vehicle and Spot classes and handle charging logic inside existing methods.

Solution

  1. Step 1: Identify extensibility requirements

    New vehicle and spot types must be added without modifying existing classes to respect OCP.
  2. Step 2: Evaluate Java enum and class extension approach

    Adding new enum constants and creating new subclasses externally allows extension without modifying existing code. Updating compatibility map externally avoids class explosion.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Extends enums and classes externally, no existing class changes [check]
Hint: Extend enums + subclasses externally, no existing class edits [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard