โ Kembali ke Design Pattern
๐
Behavioral
Command
Membungkus sebuah request sebagai objek, sehingga operasi bisa di-undo/redo, dimasukkan ke antrean, dan dicatat.
Masalahnya
Kamu perlu mengirim request tanpa tahu operasi apa yang dijalankan, siapa yang menjalankannya, atau kapan. Kamu juga ingin mendukung undo/redo.
Cara Kerja
- โบRequest dibungkus sebagai objek dengan method execute() dan undo()
- โบMemisahkan invoker (pengirim command) dari receiver (yang menanganinya)
- โบCommand bisa dimasukkan ke antrean, dicatat, atau diputar ulang
- โบundo() membalikkan efek execute(), memungkinkan pengelolaan riwayat secara penuh
- โบMacro command menggabungkan beberapa command menjadi satu
Kapan Digunakan
โFitur undo/redo (text editor, aplikasi menggambar)
โSistem berbasis transaksi yang butuh rollback
โMengantrekan atau menjadwalkan aksi untuk dijalankan nanti
โMencatat dan mengaudit semua operasi yang dilakukan
Contoh di Dunia Nyata
๐
iOS
NSUndoManager, UIAction, SwiftUI .onTapGesture closures
๐ค
Android
Room database transactions, WorkManager Tasks, MenuItem.setOnMenuItemClickListener
๐
Web
Redux actions & reducers, CQRS command objects, job queues (Bull, Celery)
Contoh Kode
Swift
protocol Command {
func execute()
func undo()
}
class TextEditor {
private(set) var content = ""
private var history = [Command]()
func run(_ cmd: Command) { cmd.execute(); history.append(cmd) }
func undoLast() { history.popLast()?.undo() }
func appendCommand(_ text: String) -> Command {
AppendCommand(editor: self, text: text)
}
fileprivate func append(_ t: String) { content += t }
fileprivate func removeLast(_ n: Int) { content = String(content.dropLast(n)) }
}
class AppendCommand: Command {
private let editor: TextEditor
private let text: String
init(editor: TextEditor, text: String) { self.editor = editor; self.text = text }
func execute() { editor.append(text) }
func undo() { editor.removeLast(text.count) }
}
let ed = TextEditor()
ed.run(ed.appendCommand("Hello"))
ed.run(ed.appendCommand(" World"))
print(ed.content) // "Hello World"
ed.undoLast()
print(ed.content) // "Hello"