Materi Tutorial

Design Patterns Python

Design Patterns adalah solusi umum yang dapat digunakan ulang untuk masalah yang sering muncul dalam perancangan perangkat lunak. Ini bukan kode jadi, melainkan template atau panduan cara menyelesaikan masalah.

Di Python, Design Patterns seringkali lebih mudah diimplementasikan (atau bahkan sudah ada secara built-in) dibandingkan bahasa lain seperti Java atau C++.

1. Singleton Pattern

Tujuannya: Memastikan sebuah class hanya memiliki satu instance. Contoh penggunaan: Koneksi database, konfigurasi aplikasi.

class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            print("Membuat instance baru...")
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

s1 = Singleton()
s2 = Singleton()

print(s1 is s2) # True

Alternatif Pythonic menggunakan Decorator:

def singleton(cls):
    instances = {}
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class Database:
    pass

2. Factory Pattern

Tujuannya: Membuat objek tanpa menentukan kelas logika yang tepat dari objek yang akan dibuat. Contoh penggunaan: Plugin system, serialisasi data berbagai format (JSON, XML).

class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def speak(self):
        return "Meow!"

def get_pet(pet="dog"):
    """The Factory Method"""
    pets = dict(dog=Dog(), cat=Cat())
    return pets[pet]

d = get_pet("dog")
print(d.speak())

c = get_pet("cat")
print(c.speak())

3. Observer Pattern (Pub-Sub)

Tujuannya: Mendefinisikan ketergantungan one-to-many, sehingga ketika satu objek berubah, semua dependensinya diberitahu. Contoh penggunaan: Event handling, sistem notifikasi.

class Subject:
    def __init__(self):
        self._observers = []

    def attach(self, observer):
        self._observers.append(observer)

    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

class Observer:
    def update(self, message):
        raise NotImplementedError

class EmailNotifier(Observer):
    def update(self, message):
        print(f"Mengirim Email: {message}")

class SMSNotifier(Observer):
    def update(self, message):
        print(f"Mengirim SMS: {message}")

# Usage
subject = Subject()
subject.attach(EmailNotifier())
subject.attach(SMSNotifier())

subject.notify("Server Down!")
# Output:
# Mengirim Email: Server Down!
# Mengirim SMS: Server Down!

4. Strategy Pattern

Tujuannya: Mendefinisikan keluarga algoritma, membungkus masing-masing, dan membuatnya dapat dipertukarkan. Contoh penggunaan: Sorting strategy, Diskon belanja, Payment gateway.

from typing import Callable

class PaymentProcessor:
    def __init__(self, strategy: Callable[[int], None]):
        self.strategy = strategy
    
    def pay(self, amount):
        self.strategy(amount)

# Strategies
def pay_by_cc(amount):
    print(f"Membayar {amount} dengan Credit Card")

def pay_by_paypal(amount):
    print(f"Membayar {amount} dengan PayPal")

# Runtime selection
cart = PaymentProcessor(pay_by_cc)
cart.pay(100)

cart = PaymentProcessor(pay_by_paypal)
cart.pay(100)

Dalam Python, karena fungsi adalah first-class object, Strategy Pattern seringkali cukup dengan passing functions seperti di atas, tanpa perlu membuat class interface yang rumit.

5. Decorator Pattern

Seperti yang sudah dibahas di tutorial sebelumnya, pola ini memungkinkan penambahan perilaku ke objek secara dinamis. Python memiliki dukungan built-in untuk pola ini dengan sintaks @.

Kesimpulan

Edit tutorial ini