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.
Görev
KolayCommand 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.TextDocumentsı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 eklerdeleteText(int count): içeriğin sonundaki soncountkarakteri 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
Commandveexecute()metotlarına ve sanal bir yıkıcıya sahip soyut birundo()sınıfı oluşturun.Ardından iki somut komut uygulayın:
InsertCommand: BirTextDocumentreferansı 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: BirTextDocumentreferansı 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.TextEditorsınıfınız birTextDocumentreferansı tutmalı ve çalıştırılan komutların geçmişiniunique_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 eklerundo(): 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:
- Eklenecek ilk metin (dize)
- Eklenecek ikinci metin (dize)
- Silinecek karakter sayısı (tam sayı)
Bir
TextDocumentve birTextEditoroluşturun. Ardından aşağıdaki işlemleri sırayla gerçekleştirin ve her adımdan sonra içeriği gösterin:- İlk metni ekleyin, ardından içeriği gösterin
- İkinci metni ekleyin, ardından içeriği gösterin
- Belirtilen sayıda karakteri silin, ardından içeriği gösterin
- Bir kez geri alın, ardından içeriği gösterin
- 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
HelloGirdiler Code, Editor ve 6 olduğunda:
Code
CodeEditor
Code
CodeEditor
CodeHer 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;
}
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
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı11İleri Düzey OOP Kavramları
Kompozisyon ve Kalıtım KarşılaştırmasıCRTP ile Mixin YapılarıPimpl İdiyomuTür Silme (Type Erasure)Enum Sınıfları ve Güçlü TiplendirmeOOP'de İstisna YönetimiÖzel İstisna Hiyerarşileri14Tasarı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ıBir Kalıp Olarak RAII3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic KonteynerKendi başına pratik yap: Online C++ derleyicisi