Problem

Implement the singleton pattern with a twist. First, instead of storing one instance, store two instances. And in every even call of getInstance(), return the first instance and in every odd call of getInstance(), return the second instance.

Solution

Method 1 - Using Singleton Pattern

Here is the explanation:

  • instances: An array holding the two singleton instances.
  • callCount: A counter to keep track of how many times getInstance is called.
  • Private Constructor: Ensures that the class cannot be instantiated directly.
  • synchronized getInstance: Synchronisation is used to make the method thread-safe. It ensures that only one thread can execute this method at a time, avoiding the creation of multiple instances in a multi-threaded environment.
  • Modulo Operator (%): Used to alternate between the two singleton instances based on the call count.
  • Lazy Initialization: The instances are created only when they are first needed.

Code

Java
public class TwoInstanceSingleton {
    private static final TwoInstanceSingleton[] instances =
        new TwoInstanceSingleton[2];
    private static int callCount = 0;

    // Private constructor to prevent instantiation
    private TwoInstanceSingleton() {}

    public static synchronized TwoInstanceSingleton getInstance() {
        int index = callCount % 2;

        // Lazily initialize the instance
        if (instances[index] == null) {
            instances[index] = new TwoInstanceSingleton();
        }

        callCount++;
        return instances[index];
    }

    // Example usage
    public static void main(String[] args) {
        TwoInstanceSingleton obj1 = TwoInstanceSingleton.getInstance();
        TwoInstanceSingleton obj2 = TwoInstanceSingleton.getInstance();
        TwoInstanceSingleton obj3 = TwoInstanceSingleton.getInstance();
        TwoInstanceSingleton obj4 = TwoInstanceSingleton.getInstance();

        System.out.println(obj1 == obj2); // false
        System.out.println(obj1 == obj3); // true
        System.out.println(obj2 == obj4); // true
        System.out.println(obj1 == obj4); // false
    }
}
Python
class TwoInstanceSingleton:
    _instances = [None, None]
    _call_count = 0

    def __new__(cls, *args, **kwargs):
        raise RuntimeError("Call getInstance() instead")

    @classmethod
    def getInstance(cls):
        # Determine which instance to return
        index = cls._call_count % 2
        # If instance doesn't exist, create it
        if cls._instances[index] is None:
            cls._instances[index] = super().__new__(cls)
        # Increment the count
        cls._call_count += 1
        # Return the appropriate instance
        return cls._instances[index]


# Usage example:
if __name__ == "__main__":
    obj1 = TwoInstanceSingleton.getInstance()
    obj2 = TwoInstanceSingleton.getInstance()
    obj3 = TwoInstanceSingleton.getInstance()
    obj4 = TwoInstanceSingleton.getInstance()

    print(obj1 is obj2)  # False
    print(obj1 is obj3)  # True
    print(obj2 is obj4)  # True
    print(obj1 is obj4)  # False

Complexity

  • ⏰ Time complexity: O(NNNXXXNNN)
  • 🧺 Space complexity: O(NNNXXX)

Method 2 -

Code

Java
Python

Complexity

  • ⏰ Time complexity: O(NNNXXXNNN)
  • 🧺 Space complexity: O(NNNXXX)