Bird
Raised Fist0

Abstract Factory Pattern - Creating Families of Related Objects

LLDeasyInterview freq: common
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
AbstractFactory

AbstractFactory is an abstract class defining factory methods returning abstract products.

🎯 Tests whether candidate knows abstract class is used because it can hold shared state or default behavior, which interfaces cannot hold in Java.
public abstract class AbstractFactory {
    public abstract Chair createChair();
    public abstract Sofa createSofa();
    public abstract Table createTable();
}
ModernFurnitureFactory

ModernFurnitureFactory extends AbstractFactory and realizes factory methods to create concrete Modern products.

🎯 Tests realization relationship and OCP: new factories can be added without modifying AbstractFactory or Client.
public class ModernFurnitureFactory extends AbstractFactory {
    public Chair createChair() { return new ModernChair(); }
    public Sofa createSofa() { return new ModernSofa(); }
    public Table createTable() { return new ModernTable(); }
}
Chair and ModernChair

Chair is an abstract class representing product family; ModernChair extends Chair providing concrete implementation.

🎯 Tests inheritance and polymorphism: client code can use Chair reference to hold any concrete Chair subclass.
public abstract class Chair {
    public abstract void sitOn();
}
public class ModernChair extends Chair {
    public void sitOn() {
        System.out.println("Sitting on modern chair");
    }
}
Client composition with AbstractFactory

Client holds AbstractFactory as a composition relationship, owning its lifecycle and using it to create products.

🎯 Tests composition lifecycle: Client creates and owns factory instance; factory cannot exist independently.
public class Client {
    private final AbstractFactory factory;
    public Client(AbstractFactory factory) {
        this.factory = factory;
    }
    public synchronized void useFurniture() {
        Chair chair = factory.createChair();
        chair.sitOn();
    }
}
📐
Class Diagram
Class Diagram
       +----------------------+
       | <<Abstract>>         |
       | AbstractFactory      |
       |----------------------|
       | +createChair():Chair |
       | +createSofa():Sofa   |
       | +createTable():Table |
       +----------------------+
               │ ─ ─ ─►
               │
       +--------------------------+
       | ModernFurnitureFactory   |
       |--------------------------|
       | +createChair():ModernChair |
       | +createSofa():ModernSofa   |
       | +createTable():ModernTable |
       +--------------------------+
               │ extends
               │
       +----------------+
       | <<Abstract>>   |
       | Chair          |
       |----------------|
       | +sitOn():void  |
       +----------------+
               │ ─ ─ ─►
               │
       +----------------+
       | ModernChair    |
       |----------------|
       | +sitOn():void  |
       +----------------+
               │ extends
               │
       +----------------+
       | Client         |
       |----------------|
       | -factory:AbstractFactory (composition) |
       | +useFurniture():void [sync]             |
       +----------------+

This diagram illustrates the Abstract Factory pattern in Java focusing on four key classes. AbstractFactory is an abstract class defining factory methods for creating product families, chosen over interfaces because it can hold shared state or default behavior. ModernFurnitureFactory realizes AbstractFactory, demonstrating the realization relationship and enforcing the Open-Closed Principle by allowing new factories without modifying existing code. Chair is an abstract product class extended by ModernChair, showing inheritance and polymorphism for product variants. Client composes AbstractFactory, owning its lifecycle, and uses synchronized methods to safely invoke factory methods, ensuring thread-safe product creation. These design decisions highlight Java-specific mechanisms like abstract classes for shared state, realization for polymorphism, composition for lifecycle ownership, and synchronized methods for concurrency control.

Primary Focus

✓ Abstract class vs Interface + Realization + Composition lifecycle + Factory OCP

Practice

(1/5)
1. You are designing a Vehicle abstraction for a parking system. Should Vehicle be an abstract class or an interface if you need to store state like licensePlate and provide default behavior for getSize()? Why?
easy
A. Use an interface, because it allows multiple inheritance and state can be stored externally.
B. Use an interface, because interfaces can hold state and default methods provide behavior.
C. Use an abstract class, because it can hold instance variables and provide default method implementations.
D. Use an abstract class, because interfaces cannot define any methods.

Solution

  1. Step 1: Analyze state and behavior requirements

    The design requires storing state (licensePlate) and providing default behavior (getSize()).
  2. Step 2: Choose correct OOP construct

    Abstract classes can have instance variables and concrete methods with default behavior. Interfaces in Java 8+ can have default methods but cannot hold instance state. Therefore, abstract class fits the need.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Abstract class supports state and default behavior [check]
Hint: State needs abstract class; interfaces lack instance variables [check]
Common Mistakes:
2. In designing the vending machine's product selection module, should Product be modeled as an abstract class or an interface? Consider that products have shared state like price and inventory count, but different behaviors like dispense() and getDescription().
easy
A. Abstract class, because it allows sharing common state and default behavior implementations among products.
B. Abstract class, because it enforces immutability of product instances.
C. Interface, because Java interfaces can now have default methods to share code and state.
D. Interface, because all products only share behavior signatures without any shared state.

Solution

  1. Step 1: Analyze shared state and behavior

    Products share common state like price and inventory count, which requires fields and possibly default implementations.
  2. Step 2: Choose between interface and abstract class

    Abstract classes can hold state and provide default method implementations, while interfaces cannot hold instance state (only constants).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports shared state and behavior [check]
Hint: Abstract class holds state; interface only behavior signatures [check]
Common Mistakes:
3. Adding a WeekendFeeStrategy to the current parking fee system requires which minimum change to comply with SOLID principles?
medium
A. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes.
C. Modify the existing FeeStrategy interface to add a isWeekend() method and update all implementations.
D. Combine all fee strategies into one class with conditional logic for weekends.

Solution

  1. Step 1: Identify applicable SOLID principle

    The Open/Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes. respects OCP by adding a new class without modifying existing ones. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies. violates OCP by modifying ParkingLot and existing strategies with conditional logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class added, existing code unchanged -> OCP respected [check]
Hint: Add new strategy class, don't modify existing ones [check]
Common Mistakes:
4. You want to add a WeekendFeeStrategy to calculate weekend parking fees without modifying existing classes. Which SOLID principle guides the minimum change, and what is the correct approach?
medium
A. Modify the ParkingLot class to add weekend fee logic, enforcing Single Responsibility Principle.
B. Add weekend fee logic inside existing FeeStrategy implementations, following Dependency Inversion Principle.
C. Create a WeekendFeeStrategy subclass of ParkingLot to override fee calculation, following Liskov Substitution Principle.
D. Create a new WeekendFeeStrategy class implementing FeeStrategy interface, and inject it where needed, following Open/Closed Principle.

Solution

  1. Step 1: Identify the SOLID principle for extensibility

    Open/Closed Principle (OCP) requires adding new functionality without modifying existing code.
  2. Step 2: Evaluate approaches

    Creating a new FeeStrategy implementation and injecting it respects OCP and DIP; modifying ParkingLot or existing strategies violates OCP or mixes responsibilities.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New FeeStrategy class + injection -> OCP and DIP respected [check]
Hint: New strategy class + injection -> Open/Closed Principle [check]
Common Mistakes:
5. You need to add support for ElectricCar and ChargingSpot in your adapter-based parking system. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar extending Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP; no existing classes modified.
B. Modify Vehicle class to add electric-specific fields and methods, and update ParkingLot to handle charging spots.
C. Create a new adapter class ElectricCarAdapter that modifies existing Vehicle and Spot classes to support charging.
D. Add a flag isElectric to Vehicle and add charging logic inside existing adapter classes.

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-specific implementation

    Adding new enum constants and new classes extends functionality cleanly; updating compatibility map centralizes logic without class changes.
  3. Step 3: Reject options modifying existing classes

    Options B, C, and D modify existing classes or add flags, violating OCP and risking class explosion.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    New enums and classes added, existing classes unchanged [check]
Hint: Add enums and classes, avoid modifying existing ones [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