Bird
Raised Fist0

Prototype Pattern - Cloning Objects When Construction Is Expensive

LLDeasyInterview freq: medium
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/5
Prototype abstract class

Prototype is an abstract class with a synchronized clone() method and an id field.

🎯 Tests whether candidate understands abstract class is used because Prototype holds state (id) which interfaces cannot hold in Java.
public abstract class Prototype {
    protected String id;
    public synchronized abstract Prototype clone();
}
ConcretePrototypeA cloning

ConcretePrototypeA extends Prototype and overrides clone() with synchronized to ensure thread safety.

🎯 Tests if candidate knows synchronized on clone() prevents race conditions during cloning in multithreaded context.
public class ConcretePrototypeA extends Prototype {
    private int specificField;
    @Override
    public synchronized Prototype clone() {
        ConcretePrototypeA copy = new ConcretePrototypeA();
        copy.id = this.id;
        copy.specificField = this.specificField;
        return copy;
    }
}
PrototypeManager singleton

PrototypeManager is a singleton with volatile instance and synchronized getInstance() to ensure safe lazy initialization.

🎯 Tests if candidate knows volatile prevents JVM reordering and partially constructed instance visibility in double-checked locking.
public class PrototypeManager {
    private static volatile PrototypeManager instance;
    private Map<String, Prototype> prototypes = new HashMap<>();
    private PrototypeManager() {}
    public static synchronized PrototypeManager getInstance() {
        if (instance == null) {
            instance = new PrototypeManager();
        }
        return instance;
    }
    public synchronized void registerPrototype(String key, Prototype prototype) {
        prototypes.put(key, prototype);
    }
    public synchronized Prototype getPrototype(String key) {
        return prototypes.get(key);
    }
}
Composition relationship PrototypeManager -> Prototype

PrototypeManager holds a Map of Prototypes, a composition relationship with lifecycle ownership of prototypes.

🎯 Tests if candidate understands composition means PrototypeManager controls lifecycle of stored prototypes, enforcing encapsulation.
private Map<String, Prototype> prototypes = new HashMap<>();
public synchronized void registerPrototype(String key, Prototype prototype) {
    prototypes.put(key, prototype);
}
public synchronized Prototype getPrototype(String key) {
    return prototypes.get(key);
}
Client usage of PrototypeManager

Client obtains PrototypeManager singleton instance and clones prototypes via synchronized methods.

🎯 Tests if candidate knows client depends on singleton instance and synchronized clone() to safely create copies without modifying originals.
public class Client {
    public static void main(String[] args) {
        PrototypeManager manager = PrototypeManager.getInstance();
        Prototype prototype = manager.getPrototype("A");
        Prototype cloned = prototype.clone();
    }
}
📐
Class Diagram
Class Diagram
       +----------------+
       | <<Abstract>>   |
       | Prototype      |
       +----------------+
       | - id: String   |
       +----------------+
       | + clone(): Prototype [sync] |
       +----------------+
              │ extends
       +----------------------+
       | ConcreteProtoA       |
       +----------------------+
       | - specificField: int |
       +----------------------+
       | + clone(): Prototype [sync] |
       +----------------------+
              │
       +----------------------+
       | ProtoManager         |
       | <<Singleton>>        |
       +----------------------+
       | - volatile instance: ProtoManager |
       | - prototypes: Map<String, Prototype> |
       +----------------------+
       | + getInstance(): ProtoManager [sync] |
       | + registerPrototype(String, Prototype) [sync] |
       | + getPrototype(String): Prototype [sync] |
       +----------------------+
              │
       +----------------------+
       | Client               |
       +----------------------+
       |                      |
       +----------------------+
       | + main(String[]): void|
       +----------------------+

This class diagram illustrates the Prototype pattern implemented in Java with key design decisions. Prototype is an abstract class because it holds state (id) and defines a synchronized clone() method to ensure thread-safe cloning. ConcretePrototypeA realizes Prototype and overrides clone() with synchronization to prevent race conditions during object copying. PrototypeManager is a singleton with a volatile instance field and synchronized getInstance() method to guarantee safe lazy initialization and visibility across threads. It composes a Map of Prototype objects, owning their lifecycle, enforcing encapsulation and adhering to composition semantics. The Client accesses the singleton PrototypeManager and clones prototypes safely, demonstrating the pattern's usage. These decisions highlight Java-specific concurrency mechanisms and SOLID principles like Single Responsibility and Open-Closed.

Primary Focus

✓ Abstract class vs interface + Singleton volatile + Composition lifecycle + Prototype cloning method

Practice

(1/5)
1. Given a Vehicle abstraction that requires both state (e.g., speed) and behavior (e.g., accelerate()), should Vehicle be an abstract class or an interface in Java, and why?
easy
A. Vehicle should be an abstract class because interfaces cannot declare methods.
B. Vehicle should be an interface because interfaces can hold state and provide default implementations.
C. Vehicle should be an interface because abstract classes cannot have abstract methods.
D. Vehicle should be an abstract class because it can hold shared state and provide common behavior implementations.

Solution

  1. Step 1: Analyze state and behavior requirements

    Vehicle needs to hold state like speed and provide behavior like accelerate(), which requires shared fields and possibly implemented methods.
  2. Step 2: Choose between abstract class and interface

    Abstract classes can hold instance variables and provide method implementations, while interfaces (pre-Java 8) cannot hold state and only declare methods. Even with default methods, interfaces cannot hold mutable state.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    State + behavior -> abstract class fits better than interface [check]
Hint: State needs fields -> use abstract class, not interface [check]
Common Mistakes:
2. 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:
3. In a parking lot system using the Strategy pattern, if parkVehicle() is NOT synchronized, which exact thread interleaving causes double-booking of the same spot?
medium
A. Thread 1 parks vehicle; Thread 2 waits until Thread 1 finishes, then parks another vehicle.
B. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
C. Thread 1 parks vehicle; Thread 2 reads spot as occupied and waits.
D. Thread 1 and Thread 2 both crash due to deadlock.

Solution

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

    Without synchronization, Thread 1 reads spot as available but before marking it occupied, context switches to Thread 2 which also reads available.
  2. Step 2: Both threads proceed to park, causing double-booking

    Because the state update is not atomic, both threads believe the spot is free and park simultaneously.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Check-then-act gap -> double-booking due to unsynchronized parkVehicle() [check]
Hint: Check availability -> context switch -> both park -> double-booking [check]
Common Mistakes:
4. You need to add support for ElectricCar and ChargingSpot in the existing in-memory SQL database's vehicle-parking module. 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 accordingly.
B. Modify Vehicle and Spot classes to add boolean flags for electric compatibility and charging support.
C. Create new classes ElectricCar and ChargingSpot with duplicated logic from Vehicle and Spot, respectively.
D. Add a new interface ElectricCompatible and modify existing classes to implement it.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Enums can be extended with new constants without changing existing class logic. Creating new subclasses preserves existing class code.
  2. Step 2: Apply minimal change approach

    Adding new enum values and new subclasses for ElectricCar and ChargingSpot allows extension without modifying existing classes. Updating compatibility map is necessary but localized.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Extend enums + subclass + update compatibility map -> minimal change [check]
Hint: Extend enums + subclass + compatibility map update -> minimal change [check]
Common Mistakes:
5. To add ElectricCar needing ChargingSpot support in the current parking lot design, what is the minimum change that respects extensibility and avoids modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
B. Modify Vehicle class to include a boolean isElectric and add charging logic in parkVehicle().
C. Create a new ElectricVehicleManager class that handles electric cars separately from existing parking logic.
D. Add charging spot logic inside existing ParkingLot class with conditional checks for electric cars.

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot should not modify existing classes to respect Open-Closed Principle and avoid class explosion.
  2. Step 2: Evaluate minimal change approach

    Extending enums and compatibility map, plus subclassing ElectricCar, allows new types without changing existing classes, preserving extensibility.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Extending enums + subclass + compatibility map update -> minimal change [check]
Hint: Extend enums + subclass + compatibility map -> minimal invasive change [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