11 - Tasarım Desenleri
2025
class Ayarlar:
_tek_nesne = None
def __new__(cls): # Nesne yaratılmadan önce bu çalışır
if cls._tek_nesne is None: # Daha önce yaratılmadıysa...
print("Ayarlar ilk kez yaratılıyor.")
cls._tek_nesne = super().__new__(cls) # Yeni nesne yarat
cls._tek_nesne.tema = "açık"
return cls._tek_nesne # Hep saklanan nesneyi döndür
# Kullanım
ayarlar1 = Ayarlar()
print(f"Tema: {ayarlar1.tema}") # açık
ayarlar1.tema = "karanlık"
ayarlar2 = Ayarlar()
print(f"Tema: {ayarlar2.tema}") # karanlık
print(f"Aynı nesne mi? {ayarlar1 is ayarlar2}") # True
İlk seferde nesne yaratılır, sonrakilerde hep aynı nesne döndürülür.
# Ürünler
class Kopek:
def ses_cikar(self): return "Hav hav!"
class Kedi:
def ses_cikar(self): return "Miyav!"
# Yaratıcı (Fabrika) Arayüzü/Soyut Sınıfı
from abc import ABC, abstractmethod
class HayvanBarinagi(ABC):
@abstractmethod
def hayvan_yarat(self): pass # Factory Method
def hayvan_konustur(self): # Factory Method'u kullanır
hayvan = self.hayvan_yarat()
print(f"Barınak diyor ki: {hayvan.ses_cikar()}")
# Somut Yaratıcılar (Ne üreteceğini bilir)
class KopekBarinagi(HayvanBarinagi):
def hayvan_yarat(self): return Kopek()
class KediBarinagi(HayvanBarinagi):
def hayvan_yarat(self): return Kedi()
# Kullanım
KopekBarinagi().hayvan_konustur() # Hav hav!
KediBarinagi().hayvan_konustur() # Miyav!
Üst sınıf (HayvanBarinagi), hangi hayvanın yaratıldığını bilmez.
from abc import ABC, abstractmethod
# 1. Component Arayüzü (Temel Nesne)
class IKahve(ABC):
@abstractmethod
def get_aciklama(self) -> str: pass
@abstractmethod
def get_fiyat(self) -> float: pass
# 2. Concrete Component (Somut Temel Nesne)
class SadeKahve(IKahve):
def get_aciklama(self) -> str: return "Sade Kahve"
def get_fiyat(self) -> float: return 5.0
# 3. Decorator Soyut Sınıfı (Hem IKahve hem de bir IKahve referansı tutar)
class KahveDekoratoru(IKahve, ABC):
def __init__(self, sarilan_kahve: IKahve):
self._sarilan_kahve = sarilan_kahve
@abstractmethod
def get_aciklama(self) -> str: pass
@abstractmethod
def get_fiyat(self) -> float: pass
# 4. Concrete Decorators (Somut Dekorlar - Yeni özellik eklerler)
class SutEkle(KahveDekoratoru):
def get_aciklama(self) -> str:
return self._sarilan_kahve.get_aciklama() + ", Sütlü"
def get_fiyat(self) -> float:
return self._sarilan_kahve.get_fiyat() + 1.5
class SekerEkle(KahveDekoratoru):
def get_aciklama(self) -> str:
return self._sarilan_kahve.get_aciklama() + ", Şekerli"
def get_fiyat(self) -> float:
return self._sarilan_kahve.get_fiyat() + 0.5
# Kullanım
kahve1 = SadeKahve()
print(f"{kahve1.get_aciklama()}: {kahve1.get_fiyat()} TL")
kahve2 = SutEkle(SadeKahve()) # Sade kahveyi süt ile sar
print(f"{kahve2.get_aciklama()}: {kahve2.get_fiyat()} TL")
kahve3 = SekerEkle(SutEkle(SadeKahve())) # Sütlü kahveyi şeker ile sar
print(f"{kahve3.get_aciklama()}: {kahve3.get_fiyat()} TL")
Dekoratörler, nesneyi katman katman sararak yeni özellikler ekler.
# Subject (Olayı yayınlayan)
class Dugme:
def __init__(self):
self._dinleyiciler = [] # Abone olanlar
def tikla(self):
print("\nDüğmeye tıklandı!")
self._bildir()
def abone_ekle(self, dinleyici):
self._dinleyiciler.append(dinleyici)
def _bildir(self):
for dinleyici in self._dinleyiciler:
dinleyici.guncelle() # Her dinleyiciye haber ver
# Observer (Olayı dinleyen) - Arayüz (İsteğe bağlı ama iyi pratik)
from abc import ABC, abstractmethod
class IDinleyici(ABC):
@abstractmethod
def guncelle(self): pass
# Concrete Observers
class LogKaydedici(IDinleyici):
def guncelle(self): print(" -> Log: Düğmeye tıklandı.")
class EkranYenileyici(IDinleyici):
def guncelle(self): print(" -> Ekran: Arayüz güncelleniyor.")
# Kullanım
kaydet_butonu = Dugme()
logcu = LogKaydedici()
ekranci = EkranYenileyici()
kaydet_butonu.abone_ekle(logcu) # Logcu butonu dinliyor
kaydet_butonu.abone_ekle(ekranci) # Ekrancı butonu dinliyor
kaydet_butonu.tikla()
Düğme, kimin dinlediğini bilmez, sadece guncelle
metodunu çağırır.
from abc import ABC, abstractmethod
# Strategy Arayüzü
class ITasimaYontemi(ABC):
@abstractmethod
def tasi(self): pass
# Concrete Strategies
class YurumeYontemi(ITasimaYontemi):
def tasi(self): print("Yürüyerek taşınıyor.")
class BisikletYontemi(ITasimaYontemi):
def tasi(self): print("Bisikletle taşınıyor.")
# Context (Stratejiyi kullanan)
class Kurye:
def __init__(self, yontem: ITasimaYontemi):
self._yontem = yontem
def yontem_degistir(self, yeni_yontem: ITasimaYontemi):
self._yontem = yeni_yontem
def paket_gonder(self):
print("Paket gönderiliyor...")
self._yontem.tasi() # İşi seçilen yönteme devret
# Kullanım
yurume = YurumeYontemi()
bisiklet = BisikletYontemi()
kurye = Kurye(yurume) # Başlangıçta yürüyerek
kurye.paket_gonder()
kurye.yontem_degistir(bisiklet) # Yöntemi değiştir
kurye.paket_gonder()
Kurye
, taşıma işinin nasıl* yapıldığını bilmez, sadece yöntemi kullanır.*
Bir metin editöründe yazdığınız metne kalın, italik veya altı çizili gibi formatlar eklemek istiyorsunuz. Bu formatları, metnin orijinal içeriğini değiştirmeden, sanki metni sararak uygulamak ve hatta birden fazla formatı (örn: hem kalın hem italik) birleştirmek için hangi yapısal desen uygun olur?
Bir online oyun geliştiriyorsunuz. Oyuncuların başarı (achievement) kazandığında, hem oyuncunun profil sayfasının güncellenmesi hem de arkadaş listesine bildirim gönderilmesi gerekiyor. Başarı kazanma olayını (Subject), profil ve arkadaş listesi güncellemelerinden (Observer) ayırmak için hangi davranışsal desen mantıklıdır?
Uygulamanızda, kullanıcıların farklı veritabanı türlerine (MySQL, PostgreSQL, SQLite) bağlanabilmesi gerekiyor. Veritabanı bağlantısını oluşturan kodu, ana iş mantığınızdan ayırmak ve hangi veritabanı bağlantısının oluşturulacağına karar verme işini özelleştirmek için hangi yaratımsal desen kullanılabilir?