Menu
Coddy logo textTech

Komut Kalıbı

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 96 / 104.

Command kalıbı, bir isteği nesne olarak kapsüller; böylece istemcileri farklı isteklerle parametreleştirmenize, işlemleri kuyruğa almanıza veya geri alma işlevini desteklemenize olanak tanır. Bir işlemi çağıran nesneyi, işlemi nasıl gerçekleştireceğini bilen nesneden ayırır.

Örüntünün dört temel bileşeni vardır: execute() yöntemine sahip bir Command arayüzü, belirli eylemleri gerçekleştiren Concrete Commands, asıl işi yapan bir Receiver ve komutları tetikleyen bir Invoker:

#include <iostream>
#include <memory>
#include <vector>

// Alıcı - işlemleri nasıl gerçekleştireceğini bilir
class Light {
public:
    void turnOn() { std::cout << "Light is ON\n"; }
    void turnOff() { std::cout << "Light is OFF\n"; }
};

// Komut arayüzü
class Command {
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
    virtual ~Command() = default;
};

// Somut Komutlar
class LightOnCommand : public Command {
    Light& light;
public:
    LightOnCommand(Light& l) : light(l) {}
    void execute() override { light.turnOn(); }
    void undo() override { light.turnOff(); }
};

class LightOffCommand : public Command {
    Light& light;
public:
    LightOffCommand(Light& l) : light(l) {}
    void execute() override { light.turnOff(); }
    void undo() override { light.turnOn(); }
};

// Çağırıcı
class RemoteControl {
    std::vector<std::unique_ptr<Command>> history;
public:
    void pressButton(std::unique_ptr<Command> cmd) {
        cmd->execute();
        history.push_back(std::move(cmd));
    }
    
    void pressUndo() {
        if (!history.empty()) {
            history.back()->undo();
            history.pop_back();
        }
    }
};

Her komut, alıcısına bir başvuru depolar ve yürütüldüğünde uygun yöntemi çağırır. Çağıran, hangi eylemin gerçekleşeceğini bilmez - yalnızca execute() çağrısını yapar. Komutları bir geçmişte depolayarak, her komutun undo() yöntemini çağırıp geri alma işlemini kolayca uygulayabilirsiniz.

İşlemleri kuyruğa almanız, geri alma/yineleme uygulamanız veya bir isteğin gönderenini işleyicisinden ayırmanız gerektiğinde Command kullanın.

challenge icon

Görev

Kolay

Command desenini kullanarak geri alma işlevine sahip bir Metin Düzenleyici oluşturalım. Metin ekleme ve silme gibi düzenleme işlemlerinin komut nesneleri olarak kapsüllendiği, kullanıcıların eylemleri gerçekleştirdikten sonra bunları gerçek bir metin düzenleyicide olduğu gibi ters sırayla geri alabildiği bir sistem oluşturacaksınız.

Kodunuzu dört dosyaya ayıracaksınız:

  • TextDocument.h: Gerçek metin içeriğini tutan ve üzerinde değişiklik yapan alıcı sınıfı oluşturun.

    TextDocument sınıfınız belgenin içeriğini bir dize olarak saklamalıdır. Aşağıdaki metotları uygulayın:

    • insertText(const std::string& text): metni içeriğin sonuna ekler
    • deleteText(int count): içeriğin sonundaki son count karakteri kaldırır (count içerik uzunluğunu aşarsa hiçbir şey yapmaz)
    • getContent(): mevcut içeriği const referans olarak döndürür
  • Command.h: Komut arayüzünü ve somut komut sınıflarını tanımlayın.

    Saf sanal Command ve execute() metotlarına ve sanal bir yıkıcıya sahip soyut bir undo() sınıfı oluşturun.

    Ardından iki somut komut uygulayın:

    • InsertCommand: Bir TextDocument referansı ve eklenecek bir dize alır. Çalıştırıldığında metni ekler. Geri alındığında, eklenen karakterlerin sayısı kadar karakteri siler.
    • DeleteCommand: Bir TextDocument referansı ve silinecek karakter sayısını alır. Geri alma sırasında geri yükleyebilmek için silinen metni saklaması gerekir. Çalıştırıldığında sondaki karakterleri kaldırır. Geri alındığında saklanan metni yeniden ekler.
  • TextEditor.h: Komutların çalıştırılmasını ve geçmişini yöneten çağıran sınıfı oluşturun.

    TextEditor sınıfınız bir TextDocument referansı tutmalı ve çalıştırılan komutların geçmişini unique_ptr<Command> vektörü kullanarak sürdürmelidir. Şunları uygulayın:

    • executeCommand(std::unique_ptr<Command> cmd): komutu çalıştırır ve geçmişe ekler
    • undo(): en son komutu geri alır ve geçmişten kaldırır (geçmiş boşsa hiçbir şey yapmaz)
    • showContent(): mevcut belge içeriğini yazdırır veya içerik boşsa [empty] yazdırır
  • main.cpp: Command desenini geri alma işleviyle birlikte gösterin.

    Üç girdi okuyun:

    1. Eklenecek ilk metin (dize)
    2. Eklenecek ikinci metin (dize)
    3. Silinecek karakter sayısı (tam sayı)

    Bir TextDocument ve bir TextEditor oluşturun. Ardından aşağıdaki işlemleri sırayla gerçekleştirin ve her adımdan sonra içeriği gösterin:

    1. İlk metni ekleyin, ardından içeriği gösterin
    2. İkinci metni ekleyin, ardından içeriği gösterin
    3. Belirtilen sayıda karakteri silin, ardından içeriği gösterin
    4. Bir kez geri alın, ardından içeriği gösterin
    5. Bir kez daha geri alın, ardından içeriği gösterin

Örneğin, girdiler Hello, World ve 3 olduğunda:

Hello
Hello World
Hello Wo
Hello World
Hello

Girdiler Code, Editor ve 6 olduğunda:

Code
CodeEditor
Code
CodeEditor
Code

Her komutun kendisini nasıl tersine çevireceğini bildiğine dikkat edin. DeleteCommand, geri yükleyebilmek için neyi sildiğini hatırlar; InsertCommand ise geri alma sırasında tam olarak kaç karakteri kaldıracağını bilir. Command deseninin gücü budur: işlemler, saklanabilen, çalıştırılabilen ve tersine çevrilebilen birinci sınıf nesnelere dönüşür.

Kendin dene

#include <iostream>
#include <string>
#include <memory>
#include "TextDocument.h"
#include "Command.h"
#include "TextEditor.h"

int main() {
    // Girdileri oku
    std::string firstText;
    std::string secondText;
    int deleteCount;
    
    std::getline(std::cin, firstText);
    std::getline(std::cin, secondText);
    std::cin >> deleteCount;

    // TODO: Bir TextDocument ve bir TextEditor oluştur
    
    // TODO: İşlemleri sırayla gerçekleştir, her birinden sonra içeriği göster:
    // 1. İlk metni ekle, sonra içeriği göster
    // 2. İkinci metni ekle, sonra içeriği göster
    // 3. Belirtilen sayıda karakteri sil, sonra içeriği göster
    // 4. Bir kez geri al, sonra içeriği göster
    // 5. Bir kez daha geri al, sonra içeriği göster
    
    // İpucu: std::make_unique<InsertCommand>(...) ve 
    //       std::make_unique<DeleteCommand>(...) kullanarak komutlar oluştur

    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online C++ derleyicisi