The Command Design Pattern in Kotlin

The Command Design Pattern is a behavioural design pattern, and as such is responsible for making two actors communicate in an efficient and maintainable way.

Problem

Often, an object (the Sender) makes a request to another object (the Receiver). Doing this in a naive way requires the Sender to know who the Receiver is at compilation time; if the Receiver changes, you will also have to change the Sender’s code, replacing the old Receiver with the new Receiver.

To avoid this, the Sender’s request is encapsulated in a separate object: the Command.

In addition, by transforming the requests into objects, there is the possibility of inserting them into data structures like Queue and then scheduling the execution at a later time.

Main Scenarios:

  • Macro
  • Undo
  • Parallel processing
  • GUI buttons

Solution

First to all, let’s see the UML Diagram about the Command Pattern.

  • The Invoker is the class who wants execute the task.
  • The Command is the interface of a generic operation.
  • The Command Implementation is the specific operation: it knows who is the real receiver.
  • The Receiver is where the task will be executed.

The Command interface provides two methods and one attribute:
1) execute() will do the task
2) unexecute() will undo the task, useless if isReversible is false
3) isReversible attribute is set in the Command Implementation’s constructor

Not every command needs to be reversible.

Finally, let’s see how it looks like in Kotlin.

The Command interface

interface Command {
val isReversible: Boolean
fun execute()
fun unexecute()
}

The Sender

TheController is the Receiver, the class who makes the task.

//               ⬇️ ⬇️ ⬇️ ⬇️
val command: Command = MyCommand(isReversible = true)
// ⬆️ ⬆️ ⬆️ ⬆️

naiveButton.setOnClickListener { //don't use this
TheController.makeStuff()
}
naiveUndo.setOnClickListener { //don't use this
TheController.undoStuff()
}

/** The buttons DON'T KNOW who the Receiver is ! **/
correctButton.setOnClickListener {
command.execute()
}
correctUndo.setOnClickListener {
command.unexecute()
}

The Command implementation

class StuffCommand(override var isReversible: Boolean) : Command {

override fun execute() {
TheController.makeStuff()
}

override fun unexecute() {
if(!isReversible)
return
TheController.undoStuff()
}
}

Final considerations

This pattern can improve the internal quality of your app, try it and write me what do you think about via Telegram!

Github project (to copy 😉, don’t worry I will not snitch you)

Thank you for your time,
Gennaro Daniele Acciaro

Icon by Freepik

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store