Bird
Raised Fist0

Adapter Pattern - Making Incompatible Interfaces Work Together

LLDeasyInterview freq: common
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
TargetInterface and Adapter realization

Adapter realizes TargetInterface to provide a compatible interface for Client.

🎯 Tests whether candidate knows interface realization is used here because TargetInterface defines behavior without state, and Adapter implements it adapting Adaptee.
public interface TargetInterface {
    void request();
}

public class Adapter implements TargetInterface {
    private Adaptee adaptee;
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
Adapter composition with Adaptee

Adapter has a composition relationship with Adaptee, owning its lifecycle and delegating calls.

🎯 Tests whether candidate distinguishes composition (Adapter owns Adaptee) from association, enforcing lifecycle encapsulation and encapsulation principle.
public class Adapter implements TargetInterface {
    private final Adaptee adaptee; // composition: Adapter owns Adaptee
    public Adapter() {
        this.adaptee = new Adaptee();
    }
    @Override
    public void request() {
        adaptee.specificRequest();
    }
}
AdapterFactory association with Adapter

AdapterFactory creates Adapter instances and returns them as TargetInterface, decoupling Client from concrete Adapter.

🎯 Tests whether candidate understands Factory Method pattern and association relationship where AdapterFactory does not own Adapter lifecycle but creates it.
public class AdapterFactory {
    public TargetInterface createAdapter() {
        Adaptee adaptee = new Adaptee();
        return new Adapter(adaptee);
    }
}
Client association with TargetInterface

Client depends on TargetInterface abstraction, allowing it to work with any implementation including Adapter.

🎯 Tests whether candidate recognizes Dependency Inversion Principle: Client depends on abstraction, not concrete Adapter, enabling extensibility.
public class Client {
    private TargetInterface target;
    public Client(TargetInterface target) {
        this.target = target;
    }
    public void execute() {
        target.request();
    }
}
📐
Class Diagram
Class Diagram
       +----------------------+
       | <<Interface>>        |
       | TargetInterface      |
       +----------------------+
       | +request(): void     |
       +----------------------+
              ^
              |  ─ ─ ─► realization
       +----------------------+
       | Adapter              |
       +----------------------+
       | - adaptee: Adaptee   |
       +----------------------+
       | +request(): void     |
       +----------------------+
              | ◆ composition
              |
       +----------------------+
       | Adaptee              |
       +----------------------+
       | +specificRequest():  |
       |   void               |
       +----------------------+
              ^
              | ─ ─ ─► association
       +----------------------+
       | AdapterFactory       |
       +----------------------+
       | +createAdapter():    |
       |   TargetInterface    |
       +----------------------+
              | ─ ─ ─► association
       +----------------------+
       | Client               |
       +----------------------+
       | +execute(): void     |
       +----------------------+

This class diagram illustrates the Adapter pattern in Java with four key classes: TargetInterface, Adapter, Adaptee, and AdapterFactory. TargetInterface is an interface realized by Adapter, which adapts Adaptee's incompatible interface. Adapter composes Adaptee, owning its lifecycle, ensuring encapsulation and enforcing composition semantics in Java. AdapterFactory uses association to create Adapter instances, applying the Factory Method pattern to decouple Client from concrete Adapter creation. Client depends on the TargetInterface abstraction, following the Dependency Inversion Principle, allowing it to work with any TargetInterface implementation. These design decisions leverage Java-specific constructs like interface realization, composition with private final fields, and factory methods to enforce SOLID principles and lifecycle ownership.

Primary Focus

✓ Interface realization + Composition lifecycle + Factory Method pattern + Adapter usage

Practice

(1/5)
1. In designing the Reputation system for Stack Overflow, should Reputation be an abstract class or an interface, and why?
easy
A. Abstract class, because Reputation holds mutable state like points and needs default behavior
B. Interface, because Reputation only defines behavior without state, allowing multiple implementations
C. Abstract class, because interfaces cannot have methods with parameters
D. Interface, because it allows storing state variables directly

Solution

  1. Step 1: Analyze Reputation's need for state and behavior

    Reputation tracks mutable points and provides default methods like addPoints(), so it requires state and behavior.
  2. Step 2: Abstract class vs interface capabilities

    Abstract classes can hold state and provide default implementations; interfaces cannot hold instance state (prior to Java 8 default methods, but still no fields).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Mutable state + default behavior -> Abstract class [check]
Hint: Stateful behavior -> abstract class; stateless behavior -> interface [check]
Common Mistakes:
2. You want to add a WeekendBonusRule that gives players extra moves on weekends without modifying existing classes. Which SOLID principle guides the minimal change, and what is the correct approach?
medium
A. Single Responsibility Principle: add weekend logic inside the Player class.
B. Open/Closed Principle: create a new class implementing a MoveRule interface and inject it into the game engine.
C. Liskov Substitution Principle: subclass Player to WeekendPlayer with bonus logic.
D. Dependency Inversion Principle: make Player depend on concrete WeekendBonusRule.

Solution

  1. Step 1: Identify SOLID principle for extension without modification

    Open/Closed Principle (OCP) states software entities should be open for extension but closed for modification.
  2. Step 2: Evaluate approaches

    Subclassing Player to WeekendPlayer allows extension without modifying Player; injecting new MoveRule class also respects OCP but requires interface design.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Subclassing extends behavior without modifying base class [check]
Hint: Extend via subclass or interface, don't modify existing classes [check]
Common Mistakes:
3. You want to add a WeekendFeeStrategy to the existing pricing module of the in-memory SQL database's query cost estimation. Which minimum change respects the Open-Closed Principle (OCP)?
medium
A. Modify the existing FeeCalculator class to add weekend logic inside the calculateFee() method.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes.
C. Add a boolean isWeekend flag to the FeeStrategy interface and implement conditional logic in all strategies.
D. Create a subclass WeekendFeeCalculator extending FeeCalculator and override calculateFee().

Solution

  1. Step 1: Understand OCP requirements

    OCP requires software entities to be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Modify the existing FeeCalculator class to add weekend logic inside the calculateFee() method. modifies existing class, violating OCP. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing classes. adds new strategy class without modifying existing code, respecting OCP. Add a boolean isWeekend flag to the FeeStrategy interface and implement conditional logic in all strategies. adds flag to interface, forcing all implementations to change, violating OCP. Create a subclass WeekendFeeCalculator extending FeeCalculator and override calculateFee(). subclasses but may require client changes, less flexible than strategy injection.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    New strategy class + injection -> OCP respected [check]
Hint: Add new strategy class, don't modify existing code [check]
Common Mistakes:
4. The Restaurant Management System needs to support ElectricCar vehicles that require ChargingSpots. What is the minimum change to the current Java design to add this feature without modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
B. Modify Vehicle class to include a boolean isElectric field and add charging logic inside existing methods.
C. Create a new ChargingSpot class extending Spot and modify TableManager to handle charging spots explicitly.
D. Add charging logic inside the existing Spot class and modify all subclasses to support electric vehicles.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclasses without changing existing classes respects OCP and avoids class explosion.
  2. Step 2: Update compatibility externally

    Updating SpotCompatibility map outside existing classes allows new vehicle and spot types to integrate without modifying existing code.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New enums + subclass + external compatibility update -> minimal change [check]
Hint: Add enums + subclass + external map update -> minimal change [check]
Common Mistakes:
5. You need to add support for ElectricCar and ChargingSpot in the existing parking system using the Iterator pattern. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Modify Vehicle and Spot classes to include electric-specific fields and logic, then update iterators accordingly.
B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; existing classes remain unchanged.
C. Create a new ElectricVehicle interface extending Vehicle and a ChargingSpot class, then modify existing iterators to handle them.
D. Add a flag isElectric to Vehicle class and modify SpotCompatibility to check this flag during iteration.

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot should not require modifying existing classes to respect OCP.
  2. Step 2: Evaluate options

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; existing classes remain unchanged. adds new enums and classes without modifying existing ones, preserving OCP. Modify Vehicle and Spot classes to include electric-specific fields and logic, then update iterators accordingly. modifies existing classes, violating OCP. Create a new ElectricVehicle interface extending Vehicle and a ChargingSpot class, then modify existing iterators to handle them. adds interfaces but requires modifying iterators, violating OCP. Add a flag isElectric to Vehicle class and modify SpotCompatibility to check this flag during iteration. modifies Vehicle class, violating OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Adding new enums and subclasses without changing existing classes respects OCP [check]
Hint: Add new types via enums and subclasses, no existing class changes [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