Pola Command
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 91 dari 107.
Pola Command membungkus permintaan sebagai object, sehingga kamu dapat memparameterkan operasi, mengantrekannya, atau mendukung fungsi undo. Strategy membungkus algoritma, sedangkan Command membungkus seluruh tindakan beserta parameternya.
Di Go, kita mendefinisikan antarmuka Command dengan method Execute, lalu membuat perintah konkret yang menyimpan semua informasi yang diperlukan untuk melakukan suatu tindakan:
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"
}Invoker menyimpan dan menjalankan perintah tanpa mengetahui apa yang dilakukan perintah tersebut:
type RemoteControl struct {
command Command
}
func (r *RemoteControl) SetCommand(c Command) {
r.command = c
}
func (r *RemoteControl) PressButton() string {
return r.command.Execute()
}Invoker sepenuhnya terpisah dari penerima (Light):
light := &Light{}
remote := &RemoteControl{}
remote.SetCommand(&TurnOnCommand{light: light})
fmt.Println(remote.PressButton()) // Lampu menyala
remote.SetCommand(&TurnOffCommand{light: light})
fmt.Println(remote.PressButton()) // Lampu matiCommand ideal untuk menerapkan sistem undo/redo, antrean tugas, atau perekaman makro saat kamu perlu menyimpan, menunda, atau memutar ulang operasi.
Tantangan
MudahMari buat editor teks dengan fungsi undo menggunakan pola Command! Kamu akan membuat perintah yang merangkum operasi teks, sehingga editor dapat menjalankan tindakan dan membatalkannya: contoh klasik yang menunjukkan mengapa perintah sangat berguna.
Kamu akan mengatur kodemu dalam tiga file:
command.go: Definisikan interface perintah dan perintah pengeditan teks konkret.Buat interface
Commanddengan dua method:Execute() stringuntuk melakukan tindakan danUndo() stringuntuk membatalkannya.Implementasikan dua tipe perintah yang beroperasi pada
*TextEditor:InsertCommand: menyimpan pointer editor dan teks yang akan disisipkan. Execute menambahkan teks ke konten editor dan mengembalikanInserted: [text]. Undo menghapus teks itu dari akhir dan mengembalikanUndone insert: [text]DeleteCommand: menyimpan pointer editor dan jumlah karakter yang akan dihapus dari akhir. Execute menghapus karakter tersebut (dan menyimpannya untuk undo) lalu mengembalikanDeleted: [removed text]. Undo memulihkannya dan mengembalikanUndone delete: [restored text]
editor.go: Buat editor teksmu (receiver) dan invoker yang mengelola riwayat perintah.Buat struct
TextEditordengan fieldContent(string) dan methodAppend(text string)sertaDeleteLast(count int) string(mengembalikan teks yang dihapus).Buat struct
EditorInvokeryang menyimpan slice perintah yang telah dijalankan sebagai riwayat. Tambahkan method berikut:ExecuteCommand(cmd Command) string: menjalankan perintah, menambahkannya ke riwayat, dan mengembalikan hasilnyaUndoLast() string: menghapus perintah terakhir dari riwayat, memanggil Undo, dan mengembalikan hasilnya. Jika riwayat kosong, kembalikanNothing to undo
main.go: Peragakan sistem perintahmu dengan serangkaian operasi.Baca jumlah operasi. Untuk setiap operasi, baca tipe operasinya (
insert,delete, atauundo). Untuk insert, baca juga teks yang akan disisipkan. Untuk delete, baca jumlah karakter. Jalankan setiap operasi melalui invoker-mu dan cetak hasilnya. Setelah semua operasi, cetak konten akhir editor sebagaiFinal: [content].
Input berikut akan diberikan:
- Baris 1: Jumlah operasi
- Untuk setiap operasi: tipe operasi, lalu data tambahan jika diperlukan (teks untuk insert, jumlah karakter untuk delete)
Contohnya, jika diberikan:
5
insert
Hello
insert
World
delete
3
undo
undoOutputmu seharusnya:
Inserted: Hello
Inserted: World
Deleted: rld
Undone delete: rld
Undone insert: World
Final: HelloDan jika diberikan:
4
insert
Go
insert
Lang
undo
insert
!Outputmu seharusnya:
Inserted: Go
Inserted: Lang
Undone insert: Lang
Inserted: !
Final: Go!Dan jika diberikan:
2
undo
insert
TestOutputmu seharusnya:
Nothing to undo
Inserted: Test
Final: TestPerhatikan bagaimana setiap perintah merangkum semua yang diperlukan untuk melakukan dan membatalkan tindakannya. Invoker tidak mengetahui apa yang dilakukan perintah-perintah tersebut. Invoker hanya menjalankannya dan mengelola riwayat untuk mendukung undo!
Coba sendiri
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Baca jumlah operasi
line, _ := reader.ReadString('\n')
numOps, _ := strconv.Atoi(strings.TrimSpace(line))
// Buat editor dan invoker
editor := &TextEditor{}
invoker := &EditorInvoker{}
for i := 0; i < numOps; i++ {
// Baca jenis operasi
opLine, _ := reader.ReadString('\n')
opType := strings.TrimSpace(opLine)
var result string
switch opType {
case "insert":
// Baca teks yang akan disisipkan
textLine, _ := reader.ReadString('\n')
text := strings.TrimSuffix(textLine, "\n")
// TODO: Buat InsertCommand dan jalankan melalui invoker
_ = text
_ = editor
case "delete":
// Baca jumlah karakter yang akan dihapus
countLine, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countLine))
// TODO: Buat DeleteCommand dan jalankan melalui invoker
_ = count
case "undo":
// TODO: Panggil UndoLast pada invoker
}
fmt.Println(result)
}
// Cetak isi akhir
fmt.Printf("Final: %s\n", editor.Content)
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Dasar-Dasar OOP di Go
File EksternalWorkspace Go dan modulePaket dan ImporNama yang Diekspor dan Tidak DieksporPengantar OOP di Gostruct sebagai classMendefinisikan method pada structPointer receiver vs value receiverInisialisasi structFungsi KonstruktorUlasan: Kalkulator Sederhana4Interface
Pengenalan InterfaceImplementasi ImplisitInterface sebagai KontrakInterface Kosong (any)Type AssertionType SwitchKomposisi InterfaceInterface Stringer & ErrorUlasan: Kalkulator Bentuk7Enkapsulasi
Field yang Diekspor vs Tidak DieksporEnkapsulasi Tingkat PackageMethod Getter dan SetterPenyembunyian Informasi di GoRingkasan: Data Siswa10Generics (Go 1.18+)
Pengantar GenericsParameter TipeBatasan TipeStruct GenerikCara Alternatif untuk Method GenerikRingkasan Koleksi Generik2Mendalami Tipe dan Struct
Tipe Dasar dan KompositDefinisi Tipe KustomTag StructStruct AnonimStruct BersarangNilai Nol dan Nilai BawaanRangkuman: Buku Kontak5Komposisi daripada Pewarisan
Mengapa Go Tidak Memiliki PewarisanDasar Penyematan StructPromosi methodMenyematkan Beberapa StructPenyematan vs AgregasiMembayangi method yang DisematkanRangkuman: Hierarki Karyawan8Penanganan Error & OOP
Interface errorTipe Error KustomPembungkusan Error (fmt.Errorf)Error Sentinelerrors.Is() dan errors.As()Panic, Defer, dan RecoverRangkuman: Parser File11Pustaka Standar & OOP
io.Reader & io.Writersort.InterfaceAntarmuka fmt.Stringerencoding/json dengan StructAntarmuka http.HandlerRingkasan, Model REST API14Pola Desain Bagian 2
Pola CommandPola AdapterPola DecoratorPola Template MethodPola StatePola CompositeMiddleware sebagai Decorator3Pointer dan Memori
Dasar-Dasar Pointer di GoPointer ke StructPass by Value vs ReferenceFungsi new()Garbage Collection di GoRekap: Pembuat Linked List6Polimorfisme di Go
Polimorfisme melalui InterfaceDuck Typing di GoAturan Pemenuhan InterfaceKoleksi PolimorfikInjeksi DependensiRangkuman: Pemroses Pembayaran9Konkruensi & OOP
Dasar-dasar GoroutineChannel & KomunikasiChannel Ber-buffer vs Tanpa BufferPernyataan selectsync.Mutex & sync.RWMutexsync.WaitGroupDesain Struct yang Aman untuk ThreadRingkasan: Worker PoolLatihan sendiri: Compiler Go online