'''
Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance.

pros:
You can be sure that a class has only a single instance.
You gain a global access point to that instance.
The singleton object is initialized only when it’s requested for the first time.

cons:
Violates the Single Responsibility Principle. The pattern solves two problems at the time.
The Singleton pattern can mask bad design, for instance, when the components of the program know too much about each other.
The pattern requires special treatment in a multithreaded environment so that multiple threads won’t create a singleton object several times.
It may be difficult to unit test the client code of the Singleton because many test frameworks rely on inheritance when producing mock objects. Since the constructor of the singleton class is private and overriding static methods is impossible in most languages, you will need to think of a creative way to mock the singleton. Or just don’t write the tests. Or don’t use the Singleton pattern.

'''

from __future__ import annotations
from typing import Optional


class SingletonMeta(type):
    """
    The Singleton class can be implemented in different ways in Python. Some
    possible methods include: base class, decorator, metaclass. We will use the
    metaclass because it is best suited for this purpose.
    """

    _instance: Optional[Singleton] = None

    def __call__(self) -> Singleton:
        if self._instance is None:
            self._instance = super().__call__()
        return self._instance


class Singleton(metaclass=SingletonMeta):
    def some_business_logic(self):
        """
        Finally, any singleton should define some business logic, which can be
        executed on its instance.
        """

        # ...


if __name__ == "__main__":
    # The client code.

    s1 = Singleton()
    s2 = Singleton()

    if id(s1) == id(s2):
        print("Singleton works, both variables contain the same instance.")
        print(id(s1))
    else:
        print("Singleton failed, variables contain different instances.")