Komut Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 91 / 107.
Command kalıbı, bir isteği nesne olarak kapsüller ve işlemleri parametreleştirmenize, kuyruğa almanıza veya geri alma işlevini desteklemenize olanak tanır. Strategy algoritmaları kapsüllerken Command, parametreleriyle birlikte tüm eylemleri kapsüller.
Go'da, Execute metoduna sahip bir Command arayüzü tanımlar, ardından bir eylemi gerçekleştirmek için gereken tüm bilgileri içeren somut komutlar oluştururuz:
type Command interface {
Execute() string
}
type Light struct {
IsOn bool
}
type TurnOnCommand struct {
light *Light
}
func (c *TurnOnCommand) Execute() string {
c.light.IsOn = true
return "Light turned on"
}
type TurnOffCommand struct {
light *Light
}
func (c *TurnOffCommand) Execute() string {
c.light.IsOn = false
return "Light turned off"
}Bir çağırıcı, ne yaptıklarını bilmeden komutları saklar ve çalıştırır:
type RemoteControl struct {
command Command
}
func (r *RemoteControl) SetCommand(c Command) {
r.command = c
}
func (r *RemoteControl) PressButton() string {
return r.command.Execute()
}Çağıran, alıcıdan (Light) tamamen bağımsızdır:
light := &Light{}
remote := &RemoteControl{}
remote.SetCommand(&TurnOnCommand{light: light})
fmt.Println(remote.PressButton()) // Işık açıldı
remote.SetCommand(&TurnOffCommand{light: light})
fmt.Println(remote.PressButton()) // Işık kapatıldıCommand, geri alma/yineleme sistemleri, görev kuyrukları veya işlemleri depolamanız, geciktirmeniz ya da yeniden oynatmanız gereken makro kaydı için idealdir.
Görev
KolayKomut kalıbını kullanarak geri alma işlevine sahip bir metin düzenleyici oluşturalım! Metin işlemlerini kapsülleyen komutlar oluşturacak, böylece düzenleyici eylemleri gerçekleştirip geri alabilecek: Komutların neden bu kadar güçlü olduğunu gösteren klasik bir kullanım örneği.
Kodunu üç dosyaya ayıracaksın:
command.go: Komut arayüzünü ve somut metin düzenleme komutlarını tanımla.İki yöntemi olan bir
Commandarayüzü oluştur: Eylemi gerçekleştirmek içinExecute() stringve eylemi geri almak içinUndo() string.Bir
*TextEditorüzerinde çalışan iki komut türü uygula:InsertCommand: düzenleyici işaretçisini ve eklenecek metni tutar. Execute, metni düzenleyicinin içeriğine ekler veInserted: [text]döndürür. Undo, bu metni sondan kaldırır veUndone insert: [text]döndürür.DeleteCommand: düzenleyici işaretçisini ve sondan silinecek karakter sayısını tutar. Execute, karakterleri kaldırır (geri alma için saklar) veDeleted: [removed text]döndürür. Undo, karakterleri geri yükler veUndone delete: [restored text]döndürür.
editor.go: Metin düzenleyicini (alıcıyı) ve komut geçmişini yöneten çağırıcıyı oluştur.Bir
Contentalanı (string) veAppend(text string)ileDeleteLast(count int) stringyöntemleri (silinen metni döndürür) olan birTextEditoryapısı oluştur.Geçmiş olarak yürütülen komutların bir dilimini tutan bir
EditorInvokeryapısı oluştur. Şu yöntemleri ekle:ExecuteCommand(cmd Command) string: komutu yürütür, geçmişe ekler ve sonucu döndürür.UndoLast() string: geçmişten son komutu kaldırır, onun Undo yöntemini çağırır ve sonucu döndürür. Geçmiş boşsaNothing to undodöndürür.
main.go: Bir dizi işlemle komut sistemini göster.İşlem sayısını oku. Her işlem için işlem türünü (
insert,deleteveyaundo) oku. insert için eklenecek metni de oku. delete için karakter sayısını oku. Her işlemi çağırıcın üzerinden yürüt ve sonucu yazdır. Tüm işlemlerden sonra düzenleyicinin son içeriğiniFinal: [content]olarak yazdır.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: İşlem sayısı
- Her işlem için: işlem türü, ardından gerekiyorsa ek veri (insert için metin, delete için sayı)
Örneğin, şu girdi verildiğinde:
5
insert
Hello
insert
World
delete
3
undo
undoÇıktın şöyle olmalıdır:
Inserted: Hello
Inserted: World
Deleted: rld
Undone delete: rld
Undone insert: World
Final: HelloVe şu girdi verildiğinde:
4
insert
Go
insert
Lang
undo
insert
!Çıktın şöyle olmalıdır:
Inserted: Go
Inserted: Lang
Undone insert: Lang
Inserted: !
Final: Go!Ve şu girdi verildiğinde:
2
undo
insert
TestÇıktın şöyle olmalıdır:
Nothing to undo
Inserted: Test
Final: TestHer komutun, eylemini hem gerçekleştirmek hem de geri almak için gereken her şeyi nasıl kapsüllediğine dikkat et. Çağırıcı komutların ne yaptığını bilmez. Yalnızca onları yürütür ve geri alma desteği için geçmişi tutar!
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// İşlem sayısını oku
line, _ := reader.ReadString('\n')
numOps, _ := strconv.Atoi(strings.TrimSpace(line))
// Editor ve invoker nesnelerini oluştur
editor := &TextEditor{}
invoker := &EditorInvoker{}
for i := 0; i < numOps; i++ {
// İşlem türünü oku
opLine, _ := reader.ReadString('\n')
opType := strings.TrimSpace(opLine)
var result string
switch opType {
case "insert":
// Eklenecek metni oku
textLine, _ := reader.ReadString('\n')
text := strings.TrimSuffix(textLine, "\n")
// TODO: Bir InsertCommand oluştur ve invoker aracılığıyla çalıştır
_ = text
_ = editor
case "delete":
// Silinecek karakter sayısını oku
countLine, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countLine))
// TODO: Bir DeleteCommand oluştur ve invoker aracılığıyla çalıştır
_ = count
case "undo":
// TODO: invoker üzerinde UndoLast metodunu çağır
}
fmt.Println(result)
}
// Son içeriği yazdır
fmt.Printf("Final: %s\n", editor.Content)
}
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
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı11Standart Kütüphane ve OOP
io.Reader ve io.Writersort.Interface Arayüzüfmt.Stringer ArayüzüStruct'lar ile encoding/jsonhttp.Handler ArayüzüÖzet - REST API Modelleri14Tasarı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ıDekoratör olarak Middleware3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker PoolKendi başına pratik yap: Online Go derleyicisi