Python / Design Patterns Python-д

Design Patterns Python-д

Програм хангамжийн инженерчлэлд байнга давтагдах асуудлуудын батлагдсан шийдлүүдийг design pattern гэнэ. Эдгээрийг 1994 онд "Gang of Four" хочтой дөрвөн инженер номондоо нийтлэснээс хойш бүх хэлний хөгжүүлэгчид хэрэглэж ирсэн. Design pattern сурах нь зөвхөн Python биш — аливаа хэлнээ шилжихэд ч тустай ойлголт.

Singleton — нэг л instance

Тодорхой класс програмд ганцхан удаа үүсэх ёстой тохиолдолд Singleton pattern хэрэглэнэ. Тохиргоо унших, лог хөтлөх, өгөгдлийн сангийн холболт — эдгээр нь сонгодог жишээ:

python
class TохиргооУдирдагч:
    _instance: "TохиргооУдирдагч | None" = None

    def __new__(cls) -> "TохиргооУдирдагч":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._тохиргоо = {}
        return cls._instance

    def тохиргоо_тавих(self, түлхүүр: str, утга: str) -> None:
        self._тохиргоо[түлхүүр] = утга

    def тохиргоо_авах(self, түлхүүр: str) -> str:
        return self._тохиргоо.get(түлхүүр, "")


# Хэдэн удаа үүсгэсэн ч нэг л объект буцаана
a = TохиргооУдирдагч()
b = TохиргооУдирдагч()

a.тохиргоо_тавих("ХЭРЭГЛЭГЧ", "Болд")
print(b.тохиргоо_авах("ХЭРЭГЛЭГЧ"))   # Болд
print(a is b)                          # True — яг нэг объект

Factory — объект үүсгэх логик тусгаарлах

Ямар объект үүсгэхийг ажиллах үед шийдэхэд Factory pattern хэрэглэнэ. Объект үүсгэх кодыг ашиглах кодоос тусгаарладаг тул шинэ төрөл нэмэхэд одоо байгаа кодыг өөрчлөхгүй:

python
from __future__ import annotations

class Мэдэгдэл:
    def илгээх(self, текст: str) -> None:
        raise NotImplementedError


class ИмэйлМэдэгдэл(Мэдэгдэл):
    def илгээх(self, текст: str) -> None:
        print(f"📧 Имэйл: {текст}")


class SMSМэдэгдэл(Мэдэгдэл):
    def илгээх(self, текст: str) -> None:
        print(f"📱 SMS: {текст}")


class PushМэдэгдэл(Мэдэгдэл):
    def илгээх(self, текст: str) -> None:
        print(f"🔔 Push: {текст}")


def мэдэгдэл_үүсгэх(төрөл: str) -> Мэдэгдэл:
    сонголт = {
        "имэйл": ИмэйлМэдэгдэл,
        "sms":   SMSМэдэгдэл,
        "push":  PushМэдэгдэл,
    }
    if төрөл not in сонголт:
        raise ValueError(f"Тодорхойгүй төрөл: {төрөл}")
    return сонголт[төрөл]()


# Ашиглах
for төрөл in ["имэйл", "sms", "push"]:
    мэдэгдэл = мэдэгдэл_үүсгэх(төрөл)
    мэдэгдэл.илгээх("Таны захиалга баталгаажлаа!")

Observer — өөрчлөлтийг дамжуулах

Нэг объектын өөрчлөлтийг хэд хэдэн объектод мэдэгдэх шаардлагатай үед Observer pattern хэрэглэнэ. Event system, real-time мэдэгдэл зэргийн суурь:

python
from typing import Protocol

class Ажиглагч(Protocol):
    def шинэчлэх(self, үйл_явдал: str) -> None: ...


class ДэлгүүрийнМэдэгдэгч:
    def __init__(self) -> None:
        self._ажиглагчид: list[Ажиглагч] = []

    def бүртгэх(self, ажиглагч: Ажиглагч) -> None:
        self._ажиглагчид.append(ажиглагч)

    def мэдэгдэх(self, үйл_явдал: str) -> None:
        for ажиглагч in self._ажиглагчид:
            ажиглагч.шинэчлэх(үйл_явдал)

    def захиалга_баталгаажуулах(self, захиалга_id: str) -> None:
        print(f"Захиалга #{захиалга_id} баталгаажлаа.")
        self.мэдэгдэх(f"ЗАХИАЛГА_БАТАЛГААЖСАН:{захиалга_id}")


class ИмэйлСервис:
    def шинэчлэх(self, үйл_явдал: str) -> None:
        print(f"  ИмэйлСервис → '{үйл_явдал}' имэйл илгээлээ")


class LogСервис:
    def шинэчлэх(self, үйл_явдал: str) -> None:
        print(f"  LogСервис → '{үйл_явдал}' бүртгэлд хадгаллаа")


мэдэгдэгч = ДэлгүүрийнМэдэгдэгч()
мэдэгдэгч.бүртгэх(ИмэйлСервис())
мэдэгдэгч.бүртгэх(LogСервис())
мэдэгдэгч.захиалга_баталгаажуулах("A-4821")

Эдгээр гурван pattern бол хамгийн нийтлэг хэрэглэгддэг хэсэг. Бодит кодоо бичихдээ pattern нэрийг цохон дурдах шаардлагагүй — зүгээр л тохирсон бүтцийг хэрэглэнэ. Pattern гэдэг хэл биш, сэтгэлгээний арга юм.

Дараагийн хичээлд:

Кодоо зөвхөн ажиллуулаад зогсохгүй хурдан ажиллуулах аргуудыг сурна — timeit, cProfile, list comprehension, generator, lru_cache зэргийг ашиглан гүйцэтгэлийн оновчлол хийнэ.