Command Pattern (Komut Tasarım Kalıbı), bir isteği nesne olarak kapsülleyerek istek gönderen (invoker) ile isteği yerine getiren (receiver) arasındaki bağımsızlığı sağlayan bir davranışsal (behavioral) tasarım desenidir. Bu desen, geri alma (undo), yeniden yapma (redo) ve işlemleri sıraya koyma gibi işlevleri kolaylaştırır.
Ne Zaman Kullanılmalıdır?
Command Pattern şu durumlarda kullanışlıdır:
- İstekleri nesne olarak yönetmek gerektiğinde.
- Geri alma (undo) ve tekrar yapma (redo) işlemleri uygulanması gerektiğinde.
- İşlemleri sıraya koyma (queue) ve gecikmeli çalıştırma gerektiğinde.
- İstemci ile alıcı arasındaki bağımlılığı azaltmak istendiğinde.
- Makro komutlar (birden fazla işlemi tek bir komutta birleştirme) kullanılması gerektiğinde.
Command Pattern’in Avantajları ve Dezavantajları
Avantajlar:
- Düşük bağımlılık: Komut gönderen ve alıcı birbirinden ayrılmıştır.
- Undo/Redo işlemlerini kolaylaştırır.
- İşlemleri sıraya koymayı ve gecikmeli çalıştırmayı destekler.
- Makro komutları (birden fazla işlemi tek bir komut olarak çalıştırma) kolaylaştırır.
Dezavantajlar:
- Her işlem için ayrı bir komut sınıfı tanımlanması gerektiği için karmaşıklık artabilir.
- Ekstra nesne oluşturma maliyeti doğurabilir.
Command Pattern Kullanım Biçimleri
1. Komut Arayüzü ve Concrete Command Sınıfları
// Komut Arayüzü
interface Command {
void execute();
}
// Alıcı (Receiver) Sınıfı
class Light {
public void turnOn() {
System.out.println("Lamba açıldı.");
}
public void turnOff() {
System.out.println("Lamba kapatıldı.");
}
}
// Concrete Command: Lambayı Açma
class TurnOnCommand implements Command {
private Light light;
public TurnOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
// Concrete Command: Lambayı Kapatma
class TurnOffCommand implements Command {
private Light light;
public TurnOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
2. Invoker (Komutları Yöneten Sınıf)
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
3. Kullanım
public class Main {
public static void main(String[] args) {
Light light = new Light();
Command turnOn = new TurnOnCommand(light);
Command turnOff = new TurnOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(turnOn);
remote.pressButton();
remote.setCommand(turnOff);
remote.pressButton();
}
}
Çıktı:
Lamba açıldı.
Lamba kapatıldı.
Gerçek Dünya Senaryosu: Undo/Redo Mekanizması
import java.util.Stack;
// Undo/Redo desteği olan Command Arayüzü
interface UndoableCommand {
void execute();
void undo();
}
// Receiver
class Document {
private String text = "";
public void write(String newText) {
text += newText;
}
public void eraseLast(int length) {
text = text.substring(0, text.length() - length);
}
public String getText() {
return text;
}
}
// Concrete Command: Yazı Ekleme
class WriteCommand implements UndoableCommand {
private Document document;
private String text;
public WriteCommand(Document document, String text) {
this.document = document;
this.text = text;
}
@Override
public void execute() {
document.write(text);
}
@Override
public void undo() {
document.eraseLast(text.length());
}
}
// Invoker: Komut Yöneticisi
class CommandManager {
private Stack<UndoableCommand> commandHistory = new Stack<>();
public void executeCommand(UndoableCommand command) {
command.execute();
commandHistory.push(command);
}
public void undoLastCommand() {
if (!commandHistory.isEmpty()) {
commandHistory.pop().undo();
}
}
}
// Kullanım
public class Main {
public static void main(String[] args) {
Document doc = new Document();
CommandManager manager = new CommandManager();
UndoableCommand writeHello = new WriteCommand(doc, "Hello ");
UndoableCommand writeWorld = new WriteCommand(doc, "World!");
manager.executeCommand(writeHello);
manager.executeCommand(writeWorld);
System.out.println("Belge içeriği: " + doc.getText());
manager.undoLastCommand();
System.out.println("Undo sonrası içerik: " + doc.getText());
}
}
Çıktı:
Belge içeriği: Hello World!
Undo sonrası içerik: Hello
Sonuç
Command Pattern, bir işlemi nesne olarak sarmalayarak kodun esnekliğini artırır ve özellikle geri alma (undo), yeniden yapma (redo) ve işlem sıralama (queueing) gibi senaryolarda kullanışlıdır. Gerçek dünyada şu senaryolarda yaygın olarak kullanılır:
- Grafik editörlerinde (Photoshop, Illustrator) geri alma/yeniden yapma işlemleri
- Veritabanı işlem sıralamaları
- Makro komutları (birden fazla işlemi tek bir komutta birleştirme)
- Oyun geliştirme (karakter hareketleri, geri alma işlemleri)
Command Pattern sayesinde işlemleri daha modüler, esnek ve yönetilebilir hale getirebilirsin. 🚀