---
title: "CP5 - Singleton - Learn Design Pattern From Simple Things"
description: "Maintain one phone line indefinitely instead of repeatedly connecting and disconnecting. Learn the Singleton design pattern from simple things."
pubDate: "2022-12-25"
lang: "en"
slug: "cp5-singleton-learn-design-pattern-from-simple-things"
url: "https://hoangyell.com/cp5-singleton-learn-design-pattern-from-simple-things/"
author: "HoangYell"
categories: ["Software Craft"]
tags: ["design-patterns", "creational-patterns"]
heroImage: "https://raw.githubusercontent.com/HoangGeek/store/main/webp/FVUigNC.webp"
---

_Singleton is a **creational** design pattern:_
🖤🖤🖤🖤🤍

## What is Singleton?

Singleton is a technique that ensures only one instance can be created and accessed globally throughout a system. 
It's commonly used for coordination and centralization of resources or services, and it helps improve efficiency and consistency.

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/223170566-1d2c85ea-ff4e-4d03-a231-85640e916fd8.webp)

## Why use Single?
- Ensures that only one instance of a class exists throughout the system.
- Allows global access to the instance.
- Promotes coordination and centralization of resources or services.
- Helps improve efficiency and consistency of the system.

**Question:** _Why do some people consider Singleton to be an anti-pattern?_

**Answer:** _because it can introduce problems such as tight coupling, poor testability, and hidden dependencies that can make it harder to maintain and scale a system. Therefore, some designers prefer to use other design patterns or avoid Singleton in favor of more flexible and modular approaches._

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/1*dQQDhdA785QZ6ukHZ2bSNg.webp)

## When to use Singleton?

**Question:** _When do I use Singleton?_

**Answer:** _When you need to ensure that only one instance of a class is created to avoid the overhead of creating and destroying objects frequently, or you want to provide global access to it._ 

### Input:
- A class `PhoneLine` that need to restrict to a single instance.

``` python
class PhoneLine(metaclass=PhoneLineSingleton):
    def __init__(self):
        sleep(10)

    def talk(self):
        print(f"talking on the {id(self)} line")
```

### Expected Output:
- `phoneline` instance is the only instance that is used by all `employee` services.

``` shell
talking on the 69 line
talking on the 69 line
```

## How to implement Singleton?

### Non-Singleton implementation:
``` python
from time import sleep

class PhoneLine:
    def __init__(self):
        sleep(10)

    def talk(self):
        print(f"talking on the {id(self)} line")

class Employee:
    def __init__(self, phone_line):
        self.phone_line = phone_line

    def call_data_center(self):
        self.phone_line.talk()

# Example usage:
phone_line = PhoneLine()
employee1 = Employee(phone_line)
employee2 = Employee(phone_line)

# Both employees use the same phone line object but not the same instance
employee1.call_data_center()
employee2.call_data_center()
```

### Singleton Implementation:
``` python
from threading import Lock
from time import sleep

class PhoneLineSingleton(type):
    _instances = {}
    _lock = Lock()

    def __call__(cls, *args, **kwargs):
        """
        __call__ is defined in this metaclass(SingletonMeta), not in the normal_class(Singleton) itself.
        When you create an instance of the Singleton class using Singleton(), Python internally calls the __call__ method of the SingletonMeta metaclass, not the __call__ method of the Singleton class.
        In this way, the __call__ method in the metaclass is used to control the creation of instances of the Singleton class, while the __call__ method in the Singleton class can be used for other purposes, if needed.
        This separation of concerns between the metaclass and the class itself is a key feature of the singleton pattern implementation in the given code. It allows us to enforce the singleton pattern without modifying the interface or behavior of the Singleton class itself.
        """
        with cls._lock:
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances[cls] = instance
        return cls._instances[cls]

class PhoneLine(metaclass=PhoneLineSingleton):
    def __init__(self):
        sleep(10)

    def talk(self):
        print(f"talking on the {id(self)} line")

# Example usage:
phone_line_1 = PhoneLine()
phone_line_2 = PhoneLine()

# Both objects refer to the same instance
phone_line_1.talk()
phone_line_2.talk()
```

[Source Code: Singleton Implement](https://github.com/HoangYell/Design-Pattern-From-Simple-Things/blob/main/cp5_singleton.py)
