Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayPhonePeCRED

Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init

Choose your preparation mode3 modes available
🎯
Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init
mediumOOPAmazonGoogleMicrosoft

Imagine a logging system where multiple parts of an application need to write logs, but all must use the same logger instance to avoid conflicts and ensure consistency.

💡 The Singleton pattern ensures only one instance of a class exists and provides a global access point. Beginners often struggle with thread safety and lazy initialization, which are crucial for real-world applications where multiple threads may try to create instances simultaneously.
📋
Problem Statement

Design and implement the Singleton pattern ensuring thread safety and lazy initialization. Your implementation should prevent multiple instances from being created in a multithreaded environment, optimize performance by minimizing synchronization overhead, and optionally use language-specific features like enums for simplicity and safety.

The singleton instance must be lazily initialized (created only when first requested).The implementation must be thread-safe to prevent multiple instances in concurrent scenarios.Avoid unnecessary synchronization after the instance is initialized.Use language idioms where applicable (e.g., enum in Java).
💡
Example
Input"Multiple threads call getInstance() concurrently"
OutputAll threads receive the same singleton instance

Despite concurrent calls, only one instance is created and shared.

  • Multiple threads call getInstance() simultaneously → only one instance created
  • No calls to getInstance() → instance is never created (lazy initialization)
  • Repeated calls to getInstance() after initialization → no synchronization overhead
  • Singleton class is subclassed or cloned → should prevent multiple instances
⚠️
Common Mistakes
Not making constructor private

Multiple instances can be created externally, breaking singleton

✅ Declare constructor as private or protected

Omitting synchronization in lazy initialization

Multiple threads may create multiple instances concurrently

✅ Add synchronization or use thread-safe constructs

Synchronizing entire getInstance() method unnecessarily

Performance degrades due to locking on every call

✅ Use double-checked locking to minimize synchronization

Not using volatile keyword with double-checked locking in Java

Instruction reordering can cause partially constructed instance to be visible

✅ Declare instance as volatile

Allowing cloning or serialization to create new instances

Singleton property is violated by multiple instances

✅ Override clone() and readResolve() methods to prevent this

🧠
Basic Singleton with Eager Initialization
💡 This approach introduces the Singleton concept simply by creating the instance at class load time. It is easy to understand but lacks lazy initialization and may waste resources if the instance is never used.

Intuition

Create the singleton instance when the class is loaded, so it is always available and thread-safe by default due to class loading guarantees.

Algorithm

  1. Declare a private static final instance of the class.
  2. Make the constructor private to prevent external instantiation.
  3. Provide a public static method to return the instance.
  4. Return the pre-created instance directly.
💡 The main challenge is understanding why the instance is created upfront and how private constructors enforce single instantiation.
</>
Code
class Singleton:
    _instance = object()  # Eagerly created dummy instance

    def __new__(cls):
        # Always return the same instance
        return cls._instance

# Driver code to test
if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
class Singleton:Defines the Singleton class to encapsulate the pattern
_instance = object() # Eagerly created dummy instanceEagerly creates a single instance at class load time
def __new__(cls):Overrides __new__ to control instance creation
return cls._instanceAlways returns the same pre-created instance
public class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static final Singleton instance = new Singleton();Eagerly creates the singleton instance at class load time
private Singleton() {}Prevents external instantiation
public static Singleton getInstance() {Provides global access to the instance
return instance;Returns the pre-created singleton instance
#include <iostream>

class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        // Directly return the eagerly initialized instance
        return instance;
    }
};

// Eager initialization
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
static Singleton* instance;Declares static pointer to hold singleton instance
Singleton() {}Private constructor to prevent external instantiation
static Singleton* getInstance() {Returns the singleton instance without checks
Singleton* Singleton::instance = new Singleton();Eagerly initializes the singleton instance
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
}

// Test
const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1 === s2); // true
Line Notes
constructor() {Controls instance creation in JavaScript
if (Singleton.instance) {Returns existing instance if already created
Singleton.instance = this;Assigns the first created instance
console.log(s1 === s2);Confirms both variables point to the same instance
⏱
Complexity
TimeO(1)
SpaceO(1)

Instance is created once at class load, so getInstance() is constant time and space.

💡 For any number of calls, the instance is reused, so performance is optimal but initialization is not lazy.
Interview Verdict: Accepted

This approach is thread-safe due to class loading guarantees but wastes resources if the instance is never used.

🧠
Lazy Initialization with Synchronized Method
💡 This approach delays instance creation until first use and ensures thread safety by synchronizing the entire method, but synchronization overhead affects performance.

Intuition

Create the instance only when needed and synchronize the method to prevent multiple threads from creating multiple instances.

Algorithm

  1. Declare a private static instance initialized to null.
  2. Make the constructor private.
  3. Provide a public static synchronized method to check and create the instance if null.
  4. Return the singleton instance.
💡 The key difficulty is understanding how synchronization prevents race conditions but can slow down access after initialization.
</>
Code
import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

# Driver code
if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
import threadingImports threading module to use locks for synchronization
_lock = threading.Lock()Creates a lock to synchronize instance creation
with cls._lock:Ensures only one thread can execute instance creation at a time
if cls._instance is None:Checks if instance needs to be created
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static Singleton instance;Declares instance without initialization for lazy loading
public static synchronized Singleton getInstance() {Synchronizes entire method to ensure thread safety
if (instance == null) {Creates instance only if it does not exist
return instance;Returns the singleton instance
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}
public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx);
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
#include <mutex>Includes mutex for thread synchronization
static std::mutex mtx;Defines mutex to protect instance creation
std::lock_guard<std::mutex> lock(mtx);Locks mutex for the scope to ensure thread safety
if (instance == nullptr) {Checks if instance needs to be created
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
Line Notes
static getInstance() {Provides a static method to get the singleton instance
if (!Singleton.instance) {Checks if instance exists before creating
Singleton.instance = new Singleton();Creates the instance lazily
return Singleton.instance;Returns the singleton instance
⏱
Complexity
TimeO(1) per call, but synchronized
SpaceO(1)

Synchronization adds overhead on every call, even after initialization.

💡 For many calls, synchronization can slow down performance despite correctness.
Interview Verdict: Accepted but suboptimal

Thread safety is guaranteed but synchronization on every call is inefficient.

🧠
Double-Checked Locking with Volatile (Optimized Lazy Initialization)
💡 This approach minimizes synchronization overhead by locking only during the first instance creation, using double-checked locking and volatile keyword to ensure visibility and ordering.

Intuition

Check if instance exists without locking first; if null, synchronize and check again before creating. This avoids locking after initialization.

Algorithm

  1. Declare a private static volatile instance initialized to null.
  2. Make the constructor private.
  3. In getInstance(), first check if instance is null without locking.
  4. If null, synchronize and check again before creating the instance.
  5. Return the singleton instance.
💡 Understanding volatile and why double-checking is necessary to avoid race conditions is the main challenge.
</>
Code
import threading

class Singleton:
    _instance = None
    _lock = threading.Lock()

    @classmethod
    def getInstance(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = cls()
        return cls._instance

    def __init__(self):
        pass

# Driver code
if __name__ == '__main__':
    s1 = Singleton.getInstance()
    s2 = Singleton.getInstance()
    print(s1 is s2)  # True
Line Notes
import threadingImports threading module to use locks for synchronization
class Singleton:Defines the Singleton class
_instance = NoneHolds the singleton instance, initially None
_lock = threading.Lock()Lock to synchronize instance creation
@classmethodDefines getInstance as a class method
def getInstance(cls):Provides global access to the singleton instance
if cls._instance is None:Double-check inside lock to prevent race condition
with cls._lock:Lock only if instance might need creation
cls._instance = cls()Create the singleton instance safely
return cls._instanceReturn the singleton instance
def __init__(self):Constructor (can be used for initialization)
public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2); // true
    }
}
Line Notes
private static volatile Singleton instance;Volatile ensures visibility and ordering of writes
private Singleton() {}Prevents external instantiation
public static Singleton getInstance() {Provides global access to the singleton instance
if (instance == null) {Double-check inside synchronized block to avoid race
synchronized (Singleton.class) {Lock only when instance might be created
instance = new Singleton();Create the singleton instance safely
return instance;Return the singleton instance
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {}
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    std::cout << (s1 == s2) << std::endl; // 1 (true)
    return 0;
}
Line Notes
if (instance == nullptr) {Double-check inside lock to prevent race
std::lock_guard<std::mutex> lock(mtx);Lock only if instance might be created
instance = new Singleton();Create the singleton instance safely
return instance;Return the singleton instance
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
Line Notes
class Singleton {Defines the Singleton class
constructor() {Controls instance creation in JavaScript
if (Singleton.instance) {Returns existing instance if already created
Singleton.instance = this;Assigns the first created instance
static getInstance() {Static method to access singleton instance
if (!Singleton.instance) {Check if instance exists before creating
Singleton.instance = new Singleton();Create instance lazily
return Singleton.instance;Return the singleton instance
⏱
Complexity
TimeO(1) amortized
SpaceO(1)

Synchronization occurs only once during initialization, subsequent calls are fast.

💡 This approach balances thread safety and performance for real-world use.
Interview Verdict: Accepted and recommended

This is the preferred pattern for thread-safe lazy initialization in many languages.

🧠
Enum Singleton (Java Specific, Thread-Safe & Simple)
💡 Using enum to implement Singleton in Java is the simplest and safest way to guarantee thread safety and prevent multiple instantiations, including against serialization and reflection.

Intuition

Enums in Java are inherently single-instance per enum constant and provide implicit thread safety and serialization guarantees.

Algorithm

  1. Define an enum with a single element representing the singleton instance.
  2. Add any methods or fields needed inside the enum.
  3. Access the singleton instance via the enum constant.
  4. Rely on JVM guarantees for thread safety and serialization.
💡 Understanding that enum constants are instantiated once by JVM is key to this approach.
</>
Code
# Enum singleton is Java-specific; Python alternative is module-level singleton
class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

if __name__ == '__main__':
    s1 = Singleton()
    s2 = Singleton()
    print(s1 is s2)  # True
Line Notes
class Singleton:Defines singleton class as Python alternative to enum singleton
_instance = NoneHolds the singleton instance, initially None
def __new__(cls):Overrides __new__ to control instance creation
if cls._instance is None:Lazy initialization without thread safety
cls._instance = super().__new__(cls)Creates the instance once
return cls._instanceReturns the singleton instance
print(s1 is s2)Verifies singleton property
public enum Singleton {
    INSTANCE;

    public void someMethod() {
        System.out.println("Singleton using enum");
    }

    public static void main(String[] args) {
        Singleton s1 = Singleton.INSTANCE;
        Singleton s2 = Singleton.INSTANCE;
        System.out.println(s1 == s2); // true
        s1.someMethod();
    }
}
Line Notes
public enum Singleton {Defines enum singleton with one instance
INSTANCE;Singleton instance guaranteed by JVM
public void someMethod() {Example method inside singleton
Singleton s1 = Singleton.INSTANCE;Access singleton instance
// Enum singleton is not idiomatic in C++, use Meyers' singleton instead
#include <iostream>

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance; // Thread-safe lazy initialization
        return instance;
    }
    void someMethod() {
        std::cout << "Singleton using static local variable" << std::endl;
    }
private:
    Singleton() {}
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

int main() {
    Singleton& s1 = Singleton::getInstance();
    Singleton& s2 = Singleton::getInstance();
    std::cout << std::boolalpha << (&s1 == &s2) << std::endl; // true
    s1.someMethod();
    return 0;
}
Line Notes
static Singleton instance;Static local variable ensures thread-safe lazy initialization
Singleton(const Singleton&) = delete;Prevents copying
Singleton& operator=(const Singleton&) = delete;Prevents assignment
return instance;Returns the singleton instance
// JavaScript does not have enums like Java; use module pattern
const Singleton = (function() {
  let instance;

  function createInstance() {
    return { someMethod: () => console.log('Singleton instance') };
  }

  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Test
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true
s1.someMethod();
Line Notes
let instance;Holds the singleton instance privately
function createInstance() {Creates the singleton object
if (!instance) {Lazy initialization on first call
return instance;Returns the singleton instance
⏱
Complexity
TimeO(1)
SpaceO(1)

Instance is created once by JVM or static initialization, with no synchronization overhead.

💡 This approach is the simplest and safest in Java, but language-specific.
Interview Verdict: Accepted and recommended for Java

Enum singleton is the best practice in Java for thread safety and simplicity.

📊
All Approaches - One-Glance Tradeoffs
💡 Double-checked locking is the best balance of thread safety and performance in most interviews; enum singleton is preferred in Java.
ApproachTimeSpaceStack RiskReconstructUse In Interview
1. Basic Eager InitializationO(1)O(1)NoNoExplain concept; not suitable if lazy init required
2. Lazy Initialization with Synchronized MethodO(1) but synchronized every callO(1)NoNoShow thread safety but mention performance drawback
3. Double-Checked Locking with VolatileO(1) amortized, minimal lockingO(1)NoNoPreferred approach for thread-safe lazy initialization
4. Enum Singleton (Java only)O(1)O(1)NoNoBest practice in Java; mention if language allows
💼
Interview Strategy
💡 Use this guide to understand the Singleton pattern from basic to advanced implementations, focusing on thread safety and lazy initialization, which are common interview topics.

How to Present

Step 1: Clarify the requirements - thread safety, lazy initialization, language constraints.Step 2: Present the basic eager initialization singleton to explain the core concept.Step 3: Introduce lazy initialization with synchronized method for thread safety.Step 4: Optimize with double-checked locking to reduce synchronization overhead.Step 5: Mention language-specific best practices like enum singleton in Java.

Time Allocation

Clarify: 2min → Approach: 5min → Code: 8min → Test & Discuss: 5min. Total ~20min

What the Interviewer Tests

Understanding of thread safety, synchronization, lazy initialization, and language-specific features; ability to optimize and explain tradeoffs.

Common Follow-ups

  • How to prevent cloning or reflection from creating multiple instances? → Use readResolve or throw exceptions.
  • How does volatile keyword help in double-checked locking? → Ensures visibility and prevents instruction reordering.
💡 These follow-ups test deeper understanding of thread safety and Java-specific pitfalls.
🔍
Pattern Recognition

When to Use

1. Need exactly one instance of a class globally. 2. Instance creation should be lazy or controlled. 3. Thread safety is required in concurrent environments. 4. Prevent multiple instantiations via cloning or serialization.

Signature Phrases

only one instanceglobal access pointthread-safe singletonlazy initialization

NOT This Pattern When

Static classes or global variables provide global access but do not control instantiation or lifecycle.

Similar Problems

Multiton Pattern - manages limited instances instead of oneFactory Pattern - controls object creation but not singletonDependency Injection - manages object lifecycles differently

Practice

(1/5)
1. When a class inherits from multiple classes that have a method with the same name, describe the step-by-step process the Method Resolution Order (MRO) uses to determine which method is called.
easy
A. MRO uses a linearization algorithm that merges the order of parents and their ancestors to find the method.
B. MRO searches the first parent class fully before moving to the next parent class.
C. MRO always calls the method from the last parent class listed in the inheritance.
D. MRO randomly picks the method from any parent class that defines it.

Solution

  1. Step 1: Understand naive search

    MRO does not simply search the first parent class fully before moving to the next; it uses a more sophisticated approach.
  2. Step 2: Recognize MRO linearization

    MRO uses a specific linearization (like C3 linearization) that merges parent classes and their ancestors in a consistent order.
  3. Step 3: Eliminate incorrect options

    MRO always calls the method from the last parent class listed in the inheritance is incorrect because the last parent is not always chosen; order and ancestors matter. MRO randomly picks the method from any parent class that defines it is incorrect because MRO is deterministic, not random.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    MRO merges inheritance hierarchies to find the correct method in a predictable order.
Hint: MRO = deterministic linearization of inheritance graph
Common Mistakes:
  • Assuming simple left-to-right search suffices
  • Believing last parent always overrides
  • Thinking method choice is random
2. Given the following code snippet, what will be printed when executing the last two lines?
from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardStrategy(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing credit card payment of ${amount}")

class UPIStrategy(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing UPI payment of ${amount}")

class PaymentStrategyFactory:
    @staticmethod
    def get_strategy(method):
        if method == 'CreditCard':
            return CreditCardStrategy()
        elif method == 'UPI':
            return UPIStrategy()
        else:
            raise ValueError('Invalid payment method')

class PaymentProcessor:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def pay(self, amount):
        self.strategy.pay(amount)

processor = PaymentProcessor(PaymentStrategyFactory.get_strategy('UPI'))
processor.pay(100)
easy
A. Raises ValueError: Invalid payment method
B. Processing credit card payment of $100
C. Processing net banking payment of $100
D. Processing UPI payment of $100

Solution

  1. Step 1: Trace strategy selection

    The factory method get_strategy('UPI') returns an instance of UPIStrategy.
  2. Step 2: Trace payment method call

    The pay method of UPIStrategy prints "Processing UPI payment of $100".
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Correct strategy instance leads to correct output [OK]
Hint: Factory returns correct strategy instance for method [OK]
Common Mistakes:
  • Confusing strategy returned or output string
3. Which of the following statements about the Open/Closed Principle is INCORRECT?
medium
A. OCP means you should never modify existing code once it's written
B. OCP encourages designing modules that can be extended without changing their source code
C. Abstraction and polymorphism are key enablers of OCP
D. OCP helps reduce bugs by minimizing changes to tested code

Solution

  1. Step 1: Analyze statement A

    OCP does not forbid all modifications; it encourages minimizing changes to stable, tested code but allows modifications when necessary.
  2. Step 2: Validate other statements

    Statements B, C, and D correctly describe OCP's goals and mechanisms.
  3. Step 3: Why A is incorrect

    Absolute prohibition of modification is impractical; OCP is about minimizing and isolating changes.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    OCP is about minimizing, not forbidding, modifications.
Hint: OCP minimizes, but does not forbid, code changes [OK]
Common Mistakes:
  • Interpreting OCP as no code changes ever allowed
  • Ignoring the role of abstraction in OCP
  • Underestimating OCP's impact on bug reduction
4. Identify the bug in the following Python code implementing deep copy for the Profile class:
import copy

class Profile:
    def __init__(self, name, scores):
        self.name = name
        self.scores = scores

    def __deepcopy__(self, memo):
        new_name = self.name  # Bug here
        new_scores = copy.deepcopy(self.scores, memo)
        return Profile(new_name, new_scores)

original = Profile('Alice', [10, 20])
copy_obj = copy.deepcopy(original)
copy_obj.scores.append(30)
print(original.scores)
medium
A. Line assigning new_name = self.name does not deepcopy the name string
B. Line assigning new_scores = copy.deepcopy(self.scores, memo) incorrectly copies scores
C. The __init__ method does not initialize scores properly
D. The return statement returns a new Profile instead of modifying self

Solution

  1. Step 1: Examine __deepcopy__ method

    The line new_name = self.name copies the reference to the name string instead of deep copying it.
  2. Step 2: Understand impact

    Strings are immutable in Python, so shallow copy is usually safe, but if name were a mutable object, this would cause shared references and bugs. Proper deep copy should be used for consistency.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Only new_name assignment lacks deepcopy -> subtle bug [OK]
Hint: All nested fields must be deep copied consistently [OK]
Common Mistakes:
  • Forgetting to deepcopy all nested fields, assuming immutables are safe
5. Suppose you want to extend the Command Pattern to support commands that can be executed multiple times (reused) and also support undo/redo correctly. Which modification to the invoker's undo/redo management is necessary to handle this scenario without corrupting state?
hard
A. Store only one instance of each command and reuse it for all executions, pushing it multiple times onto undo stack.
B. Clear both undo and redo stacks after every command execution to avoid reuse issues.
C. Create a new command instance for each execution and push that instance onto the undo stack, ensuring undo/redo operate on the correct state snapshot.
D. Avoid using undo/redo stacks and instead recompute state from scratch on each undo or redo.

Solution

  1. Step 1: Understand reuse implications

    Reusing the same command instance for multiple executions causes undo/redo to affect the wrong state because the command's internal state may change.
  2. Step 2: Identify correct approach

    Creating a new command instance per execution ensures each undo/redo corresponds to the exact executed command instance and its parameters.
  3. Step 3: Confirm undo/redo stack integrity

    This approach preserves correct ordering and state consistency during undo/redo operations.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    New instances per execution prevent state corruption on undo/redo [OK]
Hint: Each execution needs a fresh command instance for correct undo/redo [OK]
Common Mistakes:
  • Reusing command instances causing incorrect undos
  • Clearing stacks unnecessarily losing history
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