Creational Patterns: Enhancing Your Coding Arsenal
Tags: designpatterns, softwareengineering, python
Published: 2023-12-01 00:22:48

---
title: Creational Patterns: Enhancing Your Coding Arsenal
published: true
description: 
tags: designpatterns, softwareengineering, python
series: Design Patterns Fundamentals
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-11-30 09:20 -0300
---

[UPDATED 12/7/2023]
✨ GitHub repo with real-world use cases: https://github.com/herchila/design-patterns/tree/main/creational_patterns

## Singleton
**Purpose**: A singleton ensures that a class has only one instance and provides a global point of access to it.

**Example**: In applications that require thread management, a Singleton can be used to manage and optimize the use of threads, ensuring that threads are reused and not excessively created and destroyed.

**Basic sample**
```python
class Singleton:
    _instance = None

    @staticmethod
    def getInstance():
        if Singleton._instance == None:
            Singleton()
        return Singleton._instance

    def __init__(self):
        if Singleton._instance != None:
            raise Exception("This class is a singleton!")
        else:
            Singleton._instance = self

# Usage
s = Singleton.getInstance()
print(s)

s1 = Singleton.getInstance()
print(s1)  # Will print the same instance as s
```


**Advance sample**
The Singleton pattern can be effectively used in scenarios involving message producers in systems like Apache Kafka. Apache Kafka is a distributed streaming platform that allows for high-throughput, fault-tolerant handling of streaming data. In such a system, a Singleton can be used to manage a Kafka producer instance to ensure that only one instance is used to send messages to a Kafka topic, which can be crucial for optimizing resource usage and managing connections.

Here's an example of how you might implement a Kafka producer as a Singleton in Python:


```python
from kafka import KafkaProducer
import json

class KafkaProducerSingleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(KafkaProducerSingleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self, kafka_servers):
        # This will only be executed once
        self.producer = KafkaProducer(bootstrap_servers=kafka_servers,
                                      value_serializer=lambda v: json.dumps(v).encode('utf-8'))

    def send_message(self, topic, value):
        self.producer.send(topic, value)
        self.producer.flush()

# Usage example
kafka_servers = ['localhost:9092']  # Replace with your Kafka server addresses
producer1 = KafkaProducerSingleton(kafka_servers)
producer2 = KafkaProducerSingleton(kafka_servers)

print(producer1 == producer2)  # True

# Sending a message
producer1.send_message('my_topic', {'key': 'value'})
```

In this implementation:

The `__new__` method ensures that only one instance of `KafkaProducerSingleton` is created. If an instance already exists, it returns that existing instance.
The `__init__` method initializes the Kafka producer. This initialization only happens once since `__new__` ensures only one instance is created.
The `send_message` method is used to send messages to a specified Kafka topic. It uses the producer to send the message and then flushes the producer to ensure the message is sent immediately.


## Abstract Factory Pattern
**Purpose**: To provide an interface for creating families of related or dependent objects without specifying their concrete classes.

**Example**: A UI library where we need to create UI elements that are consistent across different operating systems.

```python
class Button:
    def paint(self): pass

class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"

class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"

class GUIFactory:
    def create_button(self): pass

class LinuxFactory(GUIFactory):
    def create_button(self):
        return LinuxButton()

class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()

# Usage
def client_code(factory: GUIFactory):
    button = factory.create_button()
    print(button.paint())

client_code(LinuxFactory())  # Output: Render a button in a Linux style
client_code(WindowsFactory())  # Output: Render a button in a Windows style
```

## Builder Pattern
**Purpose**: To separate the construction of a complex object from its representation, allowing the same construction process to create different representations.

**Example**: Building different types of documents (Text, HTML, Markdown) with the same content.

```python
class Document:
    def __init__(self):
        self.parts = []

    def add(self, part):
        self.parts.append(part)

    def __str__(self):
        return '\n'.join(self.parts)

class Builder:
    def build_title(self, title): pass
    def build_body(self, body): pass
    def get_result(self): pass

class TextBuilder(Builder):
    def __init__(self):
        self.document = Document()

    def build_title(self, title):
        self.document.add(f"Title: {title}")

    def build_body(self, body):
        self.document.add(body)

    def get_result(self):
        return self.document

# Usage
builder = TextBuilder()
builder.build_title("My Title")
builder.build_body("Hello, world!")
document = builder.get_result()
print(document)
```

## Factory Pattern
**Purpose**: To create objects without specifying the exact class of object that will be created.

**Example**: Generating different types of charts based on user input.

```python
class Chart:
    def draw(self): pass

class BarChart(Chart):
    def draw(self):
        return "Drawing a bar chart"

class PieChart(Chart):
    def draw(self):
        return "Drawing a pie chart"

def chart_factory(chart_type):
    charts = {
        "bar": BarChart,
        "pie": PieChart
    }
    return charts[chart_type]()

# Usage
chart = chart_factory("bar")
print(chart.draw())  # Output: Drawing a bar chart
```

## Prototype Pattern
**Purpose**: To create new objects by copying existing objects, thus reducing the cost of creation.

**Example**: Duplicating graphic objects in a graphic editor.

```python
import copy

class Prototype:
    def clone(self): pass

class ConcretePrototype(Prototype):
    def __init__(self, number):
        self.number = number

    def clone(self):
        return copy.deepcopy(self)

# Usage
prototype = ConcretePrototype(1)
cloned_prototype = prototype.clone()
print(cloned_prototype.number)  # Output: 1
```