Menu
CoddyTech

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.

challenge icon

Görev

Kolay

Komut 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 Command arayüzü oluştur: Eylemi gerçekleştirmek için Execute() string ve eylemi geri almak için Undo() 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 ve Inserted: [text] döndürür. Undo, bu metni sondan kaldırır ve Undone 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) ve Deleted: [removed text] döndürür. Undo, karakterleri geri yükler ve Undone 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 Content alanı (string) ve Append(text string) ile DeleteLast(count int) string yöntemleri (silinen metni döndürür) olan bir TextEditor yapısı oluştur.

    Geçmiş olarak yürütülen komutların bir dilimini tutan bir EditorInvoker yapı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şsa Nothing to undo dö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, delete veya undo) 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ğini Final: [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: Hello

Ve ş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: Test

Her 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)
}
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 Go derleyicisi