Command pattern’in temel amacı, nesnelerin arasındaki ilişki ve etkileşimleri düzenlemektedir, temelde bir istemcinin isteğini bir nesneye bağlar, bunu yapaykende isteğin hangi nesne tarafından ve nasıl işleneceği tamamen soyutlanmış durumdadır. Sonuçta elde ettiğimiz yapıda işlem istemciden gelen bir isteğe göre nesnelere bağımlı olarak gerçekleştirilecek, nesneler arasındaki bağımlılık en aza inerken, işlem daha esnek, modüler ve yeniden kullanılabilir hale gelecektir. Genel anlamda nesnelerin birbirleriyle iletişim kurarak işemler gerçekleştirmesi gereken durumlar için efektif bir çözüm olarak uygulanabilir.
Örnek bir senaryoyu ele alalım: Bir metin düzenleme uygulaması geliştirdiğinizi düşünün, kullanıcının bir butona tıklaması sonucu bir belgeyi kaydetmesi gerektiğinde, kaydetme işlemi, butona bağlı bir olay işleyici tarafından doğrudan gerçekleştirilir. Ancak, belgenin kaydedilmesi gerektiği durumlarda, farklı yerlerdeki farklı bileşenler tarafından da bu işlem tetiklenebilir. Bu durumda, kaydetme işlemi, kodun birçok yerinde tekrarlanacak ve bakımı zor hale gelecektir.
Command tasarım deseni, bu sorunu çözmek için kullanılabilir. Belgenin kaydedilmesi gerektiğinde, bir Command nesnesi oluşturulur ve bu nesne, kaydetme işlemini gerçekleştiren bir sınıfa gönderilir. Bu sayede, kaydetme işlemi, birçok farklı yerde Command nesnesi üzerinden tetiklenebilecektir.
UML diagramını inceleyecek olursak;
Command: komutların uygulanması için gereken yöntemleri tanımlayan bir arayüz veya sınıf olabilir, uygulanacak işlemin adını, parametreleri ve işlemin geri alınması için gereken bilgileri içerir.
ConcreteCommand: Command arayüzünü uygulayan sınıftır ve bir işlemi gerçekleştirmek için gerekli tüm yöntemleri ve bilgileri içerir.
Invoker: Command nesnelerinin yönetildiği bir sınıftır. Command nesnelerini alır ve bir command nesnesinin uygulanmasını talep eder.
Receiver: Bir işlemi gerçekleştirmek için kullanılan nesnedir. ConcreteCommand nesneleri, Receiver nesnesini kullanarak işlemleri gerçekleştirir.
Örnek kod üzerinden ilerlemek için şöyle bir senaryomuz olsun: Akıllı ev aletleri için uygulama geliştirdiğinizi düşünün akıllı bir ampulün uzaktan mobil cihaz üzerinden açılma, kapanma ve renk değiştirme işlemlerini yazıyor olalım.
from abc import ABC, abstractmethod
# Command abstract class
class Command(ABC):
@abstractmethod
def execute(self):
pass
# Concrete Command classes
class TurnOnCommand(Command):
def __init__(self, device):
self.device = device
def execute(self):
self.device.turn_on()
class TurnOffCommand(Command):
def __init__(self, device):
self.device = device
def execute(self):
self.device.turn_off()
class ChangeColorCommand(Command):
def __init__(self, device, color_code):
self.device = device
self.color_code = color_code
def execute(self):
self.device.change_color(self.color_code)
# Receiver class
class Light:
def turn_on(self):
print("Light is on")
def turn_off(self):
print("Light is off")
def change_color(self, color_code):
print(f"Light color is : {color_code}")
# Invoker class
class RemoteControl:
def __init__(self):
self.command = None
def set_command(self, command):
self.command = command
def press_button(self):
self.command.execute()
# Client code
if __name__ == "__main__":
# Create receiver object
light = Light()
# Create concrete command objects
turn_on = TurnOnCommand(light)
turn_off = TurnOffCommand(light)
change_color_white = ChangeColorCommand(light, 'white')
change_color_red = ChangeColorCommand(light, 'red')
# Create invoker object
remote = RemoteControl()
# Set command for invoker
remote.set_command(turn_on)
# Press button to execute command
remote.press_button()
remote.set_command(turn_off)
remote.press_button()
remote.set_command(change_color_white)
remote.press_button()
remote.set_command(change_color_red)
remote.press_button()
-----------------------------------------------------------------------
Output:
Light is on
Light is off
Light color is : white
Light color is : red
Sonuç olarak açılma, kapanma ve renk değiştirme komutlarını yaratıp, RemoteAccess classı üzerinden Light objesinin farklı methodlarını çalıştırmış olduk.
Command pattern pratikte birçok durumda kullanışlı ve etkili bir desendir ve uygun bir şekilde uygulandığında, kodu daha düzenli, modüler ve anlaşılır hale getirebilir ancak doğru bir mimari seçim olmadığı durumlarda, kodun karmaşıklığı ve bakım maliyeti doğrudan artacaktır.
Sources:
Be First to Comment