โ† 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"