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, bunları 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 bir Command arayüzü ve bir Execute yöntemi tanımlar, ardından bir eylemi gerçekleştirmek için gereken tüm bilgileri barındıran 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 yürütü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 (Işık) tamamen ayrıştırılmıştı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, işlemleri depolamanız, geciktirmeniz veya yeniden oynatmanız gereken geri alma/yineleme sistemleri, görev kuyrukları ya da makro kaydı uygulamak için idealdir.
Görev
KolayCommand pattern'ı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ştirebilecek ve geri alabilecek: komutların neden bu kadar güçlü olduğunu gösteren klasik bir kullanım örneği.
Kodunuzu üç dosyaya ayıracaksınız:
command.go: Komut arayüzünüzü ve somut metin düzenleme komutlarını tanımlayın.İki metoda sahip bir
Commandarayüzü oluşturun: eylemi gerçekleştirmek içinExecute() stringve eylemi geri almak içinUndo() string.Bir
*TextEditorüzerinde çalışan iki komut türü uygulayın: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ürDeleteCommand: düzenleyici işaretçisini ve sondan silinecek karakter sayısını tutar. Execute, bu 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üzenleyicinizi (alıcıyı) ve komut geçmişini yöneten çağırıcıyı oluşturun.Bir
TextEditoralanına (string) veContentileAppend(text string)(silinen metni döndürür) metotlarına sahip birDeleteLast(count int) stringyapısı oluşturun.Geçmiş olarak çalıştırılmış komutlardan oluşan bir dilim tutan bir
EditorInvokeryapısı oluşturun. Aşağıdaki metotları ekleyin:ExecuteCommand(cmd Command) string: komutu çalıştırır, geçmişe ekler ve sonucu döndürürUndoLast() string: son komutu geçmişten kaldırır, Undo metodunu çağırır ve sonucu döndürür. Geçmiş boşsaNothing to undodöndürür
main.go: Komut sisteminizi bir dizi işlemle gösterin.İşlem sayısını okuyun. Her işlem için işlem türünü (
insert,deleteveyaundo) okuyun. insert için eklenecek metni de okuyun. delete için karakter sayısını okuyun. Her işlemi çağırıcınız üzerinden çalıştırın ve sonucu yazdırın. Tüm işlemlerden sonra son düzenleyici içeriğiniFinal: [content]olarak yazdırın.
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 veriler (insert için metin, delete için sayı)
Örneğin, aşağıdaki girdi verildiğinde:
5
insert
Hello
insert
World
delete
3
undo
undoÇıktınız şu olmalıdır:
Inserted: Hello
Inserted: World
Deleted: rld
Undone delete: rld
Undone insert: World
Final: HelloVe aşağıdaki girdi verildiğinde:
4
insert
Go
insert
Lang
undo
insert
!Çıktınız şu olmalıdır:
Inserted: Go
Inserted: Lang
Undone insert: Lang
Inserted: !
Final: Go!Ve aşağıdaki girdi verildiğinde:
2
undo
insert
TestÇıktınız şu 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 edin. Çağırıcı, komutların ne yaptığını bilmiyor. Yalnızca onları çalıştırıyor ve geri alma desteği için geçmişi tutuyor!
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))
// Editörü ve invoker'ı 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'ı ç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