Menu
Coddy logo textTech

Komut Kalıbı

Coddy'nin Python Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 49 / 64.

Komut Deseni (Command Pattern), bir isteği bir nesne olarak kapsülleyerek işlemleri sıraya koymanıza, istekleri günlüğe kaydetmenize ve geri alma (undo) işlevini desteklemenize olanak tanır. Bu desen, işlemi çağıran nesne ile işlemi gerçekleştiren nesneyi birbirinden ayırır.

İşte basit komut sınıfları:

class Command:
    def execute(self):
        pass

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_off()

Her komut, bir alıcı nesne üzerindeki belirli bir işlemi kapsüller.

Asıl işi gerçekleştiren alıcıyı (receiver) oluşturun:

class Light:
    def turn_on(self):
        print("Light is on")
    
    def turn_off(self):
        print("Light is off")

Komutları yürüten bir çağırıcı (invoker) oluşturun:

class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

Komut desenini kullanın:

# Alıcıyı oluştur
light = Light()

# Komutları oluştur
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

# Çağırıcıyı oluştur
remote = RemoteControl()

# Farklı komutları çalıştır
remote.set_command(light_on)
remote.press_button()

remote.set_command(light_off)
remote.press_button()

Geri alma işlemleri için destek ekleyin:

class UndoableCommand(Command):
    def undo(self):
        pass

class LightOnCommand(UndoableCommand):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()
    
    def undo(self):
        self.light.turn_off()

class SmartRemote:
    def __init__(self):
        self.last_command = None
    
    def execute_command(self, command):
        command.execute()
        self.last_command = command
    
    def undo(self):
        if self.last_command:
            self.last_command.undo()

smart_remote = SmartRemote()
smart_remote.execute_command(LightOnCommand(light))
smart_remote.undo()  # Işığı kapatır

Çıktı:

Light is on
Light is off
Light is on
Light is off

Anahtar Nokta: Komut Deseni (Command Pattern), istekleri depolanabilen, aktarılabilen ve daha sonra yürütülebilen nesnelere dönüştürür. Çağırıcı (invoker), işlemin nasıl gerçekleştirileceğini bilmek zorunda değildir; sadece komut nesnesi üzerinde execute() metodunu çağırır. Bu; geri al/yinele (undo/redo), işlemleri kuyruğa alma ve komutları günlüğe kaydetme gibi özellikleri mümkün kılar.

challenge icon

Görev

Kolay

Bu meydan okumada, Komut Deseninin (Command Pattern) temel yapı taşı olan command.py içindeki temel Command taban sınıfını uygulayacaksınız. Bu alıştırma özellikle kapsüllemeye (encapsulation) odaklanır: verileri özel olarak saklamak ve bir özellik (property) aracılığıyla güvenli bir şekilde sunmak.

Sadece command.py dosyasını TODO yorumlarına göre değiştirin. TODO yorumları size şu konularda rehberlik edecektir:

  • Komut adını özel bir öznitelik (_name) olarak saklayın
  • Bunu salt okunur bir özellik (name) aracılığıyla sunun
  • Komut adını yazdıran bir display_info() yöntemi uygulayın

Not: Bu meydan okuma yalnızca temel Command sınıfını kapsar — Invoker, Receiver ve geri alma (undo) işlevselliği sonraki derslerde tanıtılacaktır. Bu adımı tamamlamak, size tam desenin üzerine inşa edildiği kapsülleme temelini sağlar.

Uygulamanız, şunları doğrulayan driver.py tarafından test edilecektir:

  • Temel işlevsellik ve çıktı formatı
  • Uç durumlar (boş girdiler, özel karakterler, uzun isimler)
  • Salt okunur özellik koruması (obj.name = ... denemesi AttributeError hatası vermelidir)
  • Özel _name özniteliğinin varlığı

Kopya kağıdı

Komut Deseni (Command Pattern), bir isteği bir nesne olarak kapsüller; bu da işlemleri kuyruğa almanıza, istekleri günlüğe kaydetmenize ve geri alma (undo) işlevini desteklemenize olanak tanır.

Temel komut yapısı:

class Command:
    def execute(self):
        pass

class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()

class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_off()

Gerçek işi gerçekleştiren bir alıcı (receiver) oluşturun:

class Light:
    def turn_on(self):
        print("Light is on")
    
    def turn_off(self):
        print("Light is off")

Komutları yürüten bir çağırıcı (invoker) oluşturun:

class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command):
        self.command = command
    
    def press_button(self):
        self.command.execute()

Kullanım örneği:

# Alıcıyı oluştur
light = Light()

# Komutları oluştur
light_on = LightOnCommand(light)
light_off = LightOffCommand(light)

# Çağırıcıyı oluştur
remote = RemoteControl()

# Farklı komutları yürüt
remote.set_command(light_on)
remote.press_button()

remote.set_command(light_off)
remote.press_button()

Geri alma (undo) işlevselliği ekleyin:

class UndoableCommand(Command):
    def undo(self):
        pass

class LightOnCommand(UndoableCommand):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        self.light.turn_on()
    
    def undo(self):
        self.light.turn_off()

class SmartRemote:
    def __init__(self):
        self.last_command = None
    
    def execute_command(self, command):
        command.execute()
        self.last_command = command
    
    def undo(self):
        if self.last_command:
            self.last_command.undo()

Kendin dene

# command.py dosyasından Command sınıfını içe aktar
from command import Command

# Kapsamlı test senaryosu işleyicisi
test_case = input()

if test_case == "basic_test":
    obj = Command("Test Name")
    obj.display_info()
elif test_case == "validation_test":
    obj = Command("Validation Test")
    print(f"Name: {obj.name}")
elif test_case == "empty_name_test":
    obj = Command("")
    obj.display_info()
    print(f"Empty name handled: {'Yes' if obj.name == '' else 'No'}")
elif test_case == "property_access_test":
    obj = Command("Property Test")
    original_name = obj.name
    try:
        # İsim salt okunur bir özellik olduğu için bu başarısız olmalıdır
        obj.name = "Modified Name"
        print("Property protection failed")
    except AttributeError:
        print("Property protected successfully")
    print(f"Name unchanged: {obj.name == original_name}")
elif test_case == "multiple_commands_test":
    commands = [
        Command("First Command"),
        Command("Second Command"),
        Command("Third Command")
    ]
    for cmd in commands:
        cmd.display_info()
elif test_case == "attribute_test":
    obj = Command("Attribute Test")
    has_private_name = hasattr(obj, "_name")
    print(f"Has _name attribute: {has_private_name}")
elif test_case == "special_chars_test":
    obj = Command("!@#$%^&*()_+{}[]|\\:;\"'<>,.?/")
    obj.display_info()
elif test_case == "long_name_test":
    long_name = "A" * 100
    obj = Command(long_name)
    obj.display_info()
    print(f"Name length: {len(obj.name)}")
quiz iconKendini test et

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