Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Command 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 Command arayüzü oluşturun: 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ü uygulayın:

    • 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, bu 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üzenleyicinizi (alıcıyı) ve komut geçmişini yöneten çağırıcıyı oluşturun.

    Bir TextEditor alanına (string) ve Content ile Append(text string) (silinen metni döndürür) metotlarına sahip bir DeleteLast(count int) string yapısı oluşturun.

    Geçmiş olarak çalıştırılmış komutlardan oluşan bir dilim tutan bir EditorInvoker yapı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ür
    • UndoLast() string: son komutu geçmişten kaldırır, Undo metodunu çağırır ve sonucu döndürür. Geçmiş boşsa Nothing to undo dö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, delete veya undo) 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ğini Final: [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: Hello

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

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