Dekoratör Kalıbı
Coddy'nin Python Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 51 / 64.
Decorator Deseni, nesnelerin yapılarını değiştirmeden onlara dinamik olarak yeni işlevsellikler ekler. Davranışlarını genişletmek için nesneleri sarmalar.
İşte basit bir kahve örneği:
class Coffee:
def cost(self):
return 5
def description(self):
return "Simple coffee"Kahveye özellikler ekleyen dekoratörler oluşturun:
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 2
def description(self):
return self.coffee.description() + " + Milk"
class SugarDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 1
def description(self):
return self.coffee.description() + " + Sugar"Her bir dekoratör başka bir nesneyi sarmalar ve kendi işlevselliğini ekler.
Özelleştirilmiş kahve oluşturmak için dekoratörleri kullanın:
# Temel kahve ile başla
my_coffee = Coffee()
print(f"{my_coffee.description()}: ${my_coffee.cost()}")
# Süt ekle
my_coffee = MilkDecorator(my_coffee)
print(f"{my_coffee.description()}: ${my_coffee.cost()}")
# Şeker ekle
my_coffee = SugarDecorator(my_coffee)
print(f"{my_coffee.description()}: ${my_coffee.cost()}")Metin biçimlendirmeli başka bir örnek oluşturun:
class Text:
def __init__(self, content):
self.content = content
def render(self):
return self.content
class BoldDecorator:
def __init__(self, text):
self.text = text
def render(self):
return f"<b>{self.text.render()}</b>"
class ItalicDecorator:
def __init__(self, text):
self.text = text
def render(self):
return f"<i>{self.text.render()}</i>"
# Biçimlendirilmiş metni adım adım oluşturun
message = Text("Hello World")
message = BoldDecorator(message)
message = ItalicDecorator(message)
print(message.render())Çıktı:
Simple coffee: $5
Simple coffee + Milk: $7
Simple coffee + Milk + Sugar: $8
<i><b>Hello World</b></i>Anahtar Nokta: Decorator Deseni, orijinal nesneyi değiştirmeden yeni davranışlar eklemek için nesneleri sarmalar. Her dekoratör, sarmalanmış nesneye bir referans tutar ve kendi işlevselliğini ekler. Bu, birçok alt sınıf oluşturmadan esnek özellik kombinasyonları için birden fazla dekoratörü birleştirmenize olanak tanır.
Görev
OrtaBu meydan okumada, bir kahve dükkanı için esnek bir kahve sipariş sistemi oluşturmak amacıyla Decorator tasarım desenini uygulayacaksınız. Decorator deseni, aynı sınıftan diğer nesnelerin davranışını etkilemeden, tekil nesnelere dinamik olarak davranış eklenmesine olanak tanır.
Bir kahve dükkanı için şu özelliklere sahip bir sistem oluşturuyorsunuz:
- Çeşitli içecek türleri sunmak (Espresso, Dark Roast, House Blend, Decaf)
- Müşterilerin içeceklerine çeşniler (Milk, Mocha, Soy, Whipped Cream) eklemesine izin vermek
- Eklenen çeşnilerle birlikte içeceklerin maliyetini hesaplamak
beverage.pydosyasındaki soyutBeveragesınıfını ve onun somut uygulamalarını tamamlayıncondiment_decorator.pydosyasındakiCondimentDecoratorsoyut sınıfını ve somut dekoratörleri uygulayın- Uygulamanızı doğrulamak için
driver.pydosyasında test senaryolarını uygulayın
Kopya kağıdı
Decorator (Dekoratör) Deseni, nesneleri davranışlarını genişletmek için sarmalayarak, yapılarını değiştirmeden nesnelere dinamik olarak yeni işlevsellikler ekler.
Bir kahve örneği ile temel yapı:
class Coffee:
def cost(self):
return 5
def description(self):
return "Simple coffee"İşlevselliği sarmalayan ve genişleten dekoratörler oluşturun:
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 2
def description(self):
return self.coffee.description() + " + Milk"
class SugarDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 1
def description(self):
return self.coffee.description() + " + Sugar"Özelleştirilmiş nesneler oluşturmak için dekoratörleri zincirleyin:
# Temel kahve ile başlayın
my_coffee = Coffee()
# Dekoratörleri ekleyin
my_coffee = MilkDecorator(my_coffee)
my_coffee = SugarDecorator(my_coffee)
print(f"{my_coffee.description()}: ${my_coffee.cost()}")
# Çıktı: Simple coffee + Milk + Sugar: $8Metin biçimlendirme örneği:
class Text:
def __init__(self, content):
self.content = content
def render(self):
return self.content
class BoldDecorator:
def __init__(self, text):
self.text = text
def render(self):
return f"<b>{self.text.render()}</b>"
class ItalicDecorator:
def __init__(self, text):
self.text = text
def render(self):
return f"<i>{self.text.render()}</i>"
# Dekoratörleri zincirleyin
message = Text("Hello World")
message = BoldDecorator(message)
message = ItalicDecorator(message)
print(message.render())
# Çıktı: <i><b>Hello World</b></i>Temel avantajlar: Çok sayıda alt sınıf oluşturmadan esnek özellik kombinasyonlarına izin verir, sarmalanmış nesneye referansı korur ve işlevselliği dinamik olarak ekler.
Kendin dene
# Gerekli tüm sınıfları içe aktar
from beverage import Espresso, HouseBlend, DarkRoast, Decaf
from condiment_decorator import Milk, Mocha, Soy, Whip
# Kapsamlı test senaryosu işleyicisi
test_case = input()
if test_case == "basic_beverage_test":
# Temel içecek işlevselliğini test et
espresso = Espresso()
print(f"Description: {espresso.get_description()}")
print(f"Cost: ${espresso.cost():.2f}")
elif test_case == "all_beverages_test":
# Tüm içecek türlerini test et
beverages = [Espresso(), HouseBlend(), DarkRoast(), Decaf()]
for beverage in beverages:
print(f"{beverage.get_description()}: ${beverage.cost():.2f}")
elif test_case == "single_condiment_test":
# Tekli garnitür süslemesini test et
espresso = Espresso()
espresso_with_milk = Milk(espresso)
print(f"Description: {espresso_with_milk.get_description()}")
print(f"Cost: ${espresso_with_milk.cost():.2f}")
elif test_case == "multiple_condiments_test":
# Çoklu garnitür süslemelerini test et
house_blend = HouseBlend()
decorated_coffee = Mocha(Soy(Whip(house_blend)))
print(f"Description: {decorated_coffee.get_description()}")
print(f"Cost: ${decorated_coffee.cost():.2f}")
elif test_case == "all_condiments_test":
# Bir içecek üzerindeki tüm garnitürleri test et
dark_roast = DarkRoast()
fully_loaded = Milk(Mocha(Soy(Whip(dark_roast))))
print(f"Description: {fully_loaded.get_description()}")
print(f"Cost: ${fully_loaded.cost():.2f}")
elif test_case == "cost_calculation_test":
# Farklı kombinasyonlar için maliyet hesaplamalarını test et
espresso = Espresso()
# Tekli eklemeler
with_milk = Milk(espresso)
with_mocha = Mocha(espresso)
print(f"Espresso: ${espresso.cost():.2f}")
print(f"Espresso + Milk: ${with_milk.cost():.2f}")
print(f"Espresso + Mocha: ${with_mocha.cost():.2f}")
elif test_case == "decoration_order_test":
# Süsleme sırasının nihai sonucu etkilemediğini test et
decaf = Decaf()
order1 = Milk(Mocha(decaf))
order2 = Mocha(Milk(decaf))
print(f"Order 1 - {order1.get_description()}: ${order1.cost():.2f}")
print(f"Order 2 - {order2.get_description()}: ${order2.cost():.2f}")
print(f"Same cost: {order1.cost() == order2.cost()}")
elif test_case == "complex_order_test":
# Karmaşık içecek siparişlerini test et
orders = [
Mocha(Whip(Espresso())),
Soy(Milk(HouseBlend())),
Whip(Mocha(Soy(DarkRoast()))),
Milk(Decaf())
]
for i, order in enumerate(orders, 1):
print(f"Order {i}: {order.get_description()}")
print(f"Cost: ${order.cost():.2f}")
print("---")
elif test_case == "double_condiment_test":
# Aynı garnitürün birden fazla kez eklenmesini test et
espresso = Espresso()
double_mocha = Mocha(Mocha(espresso))
print(f"Description: {double_mocha.get_description()}")
print(f"Cost: ${double_mocha.cost():.2f}")
elif test_case == "beverage_comparison_test":
# Aynı garnitürlere sahip farklı içeceklerin maliyetlerini karşılaştır
base_beverages = [Espresso(), HouseBlend(), DarkRoast(), Decaf()]
print("All beverages with Milk + Mocha:")
for beverage in base_beverages:
decorated = Milk(Mocha(beverage))
print(f"{decorated.get_description()}: ${decorated.cost():.2f}")
elif test_case == "condiment_cost_test":
# Bireysel garnitür maliyetlerini test et
espresso = Espresso()
base_cost = espresso.cost()
condiments = [
("Milk", Milk(espresso)),
("Mocha", Mocha(espresso)),
("Soy", Soy(espresso)),
("Whip", Whip(espresso))
]
for name, decorated in condiments:
additional_cost = decorated.cost() - base_cost
print(f"{name} adds: ${additional_cost:.2f}")
elif test_case == "cheapest_most_expensive_test":
# En ucuz ve en pahalı temel içecekleri bul
beverages = [
("Espresso", Espresso()),
("House Blend", HouseBlend()),
("Dark Roast", DarkRoast()),
("Decaf", Decaf())
]
beverages.sort(key=lambda x: x[1].cost())
print(f"Cheapest: {beverages[0][0]} - ${beverages[0][1].cost():.2f}")
print(f"Most Expensive: {beverages[-1][0]} - ${beverages[-1][1].cost():.2f}")
elif test_case == "nested_decoration_test":
# Derinlemesine iç içe geçmiş süslemeleri test et
beverage = HouseBlend()
# 5 katman süsleme ekle
decorated = Whip(Soy(Mocha(Milk(Whip(beverage)))))
print(f"Description: {decorated.get_description()}")
print(f"Cost: ${decorated.cost():.2f}")
# Garnitür sayısını say
description = decorated.get_description()
condiment_count = description.count(" + ")
print(f"Number of condiments: {condiment_count}")
elif test_case == "cost_breakdown_test":
# Detaylı maliyet dökümü
dark_roast = DarkRoast()
print(f"Base Dark Roast: ${dark_roast.cost():.2f}")
with_soy = Soy(dark_roast)
print(f"+ Soy: ${with_soy.cost():.2f}")
with_mocha = Mocha(with_soy)
print(f"+ Mocha: ${with_mocha.cost():.2f}")
with_whip = Whip(with_mocha)
print(f"+ Whip: ${with_whip.cost():.2f}")
final_cost = with_whip.cost()
print(f"Final total: ${final_cost:.2f}")
elif test_case == "description_format_test":
# Açıklama biçimlendirme tutarlılığını test et
espresso = Espresso()
test_combinations = [
Milk(espresso),
Mocha(Milk(espresso)),
Whip(Mocha(Milk(espresso))),
Soy(Whip(Mocha(Milk(espresso))))
]
for combo in test_combinations:
description = combo.get_description()
print(f"Description: '{description}'")
# Açıklamanın temel içecek adıyla başlayıp başlamadığını kontrol et
starts_correctly = description.startswith("Espresso")
print(f"Starts with base name: {starts_correctly}")
print("---")Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Object Oriented Programming bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerself ParametresiMetotlarÖzniteliklerYapıcı Metot (__init__)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımsuper() FonksiyonuMetot Geçersiz KılmaÇoklu KalıtımMetot Çözümleme SırasıÖzet - Çalışan Hiyerarşisi7Özel Metotlar
Sihirli Metotlara GirişOperatör Aşırı YüklemeKapsayıcı Sihirli MetotlarıÖzet - Özel Liste10Tasarım Kalıpları Bölüm 1
Tasarım kalıplarına girişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı13Final Meydan Okumaları
E-öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi5Çok Biçimlilik (Polymorphism)
Metot Geçersiz Kılmaya Yeniden BakışDuck TypingSoyut Sınıflar ve MetotlarArayüz TasarımıÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon ve KalıtımMixinsStatik ve Sınıf MetotlarıSınıf DekoratörleriBağlam Yöneticileri11Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit Kalıbı