Command Design Pattern in Kotlin

1. Definition

The Command Design Pattern encapsulates a request as an object, allowing for parameterization of clients with different requests, queuing of requests, and logging of operations. It also provides support for undoable operations.

In this tutorial, we will learn how to implement a Command Design Pattern using Kotlin programming language.

2. Problem Statement

You have a system where you need to issue requests to objects, but you want to decouple the sender (invoker) from the receiver (the object executing the command). Direct coupling would make the system rigid, hard to extend, and challenging to test independently.

3. Solution

Encapsulate each request as an object (a command). This allows you to decouple senders from receivers, and you can also delay, queue, or log command calls as needed.

4. Real-World Use Cases

1. GUI buttons and menu items in software applications.

2. Macro recording in software, where a series of operations can be recorded and replayed.

3. Multi-level undo and redo in software applications.

5. Implementation Steps

1. Define a command interface with an execute method.

2. Create one or more concrete classes that implement this command interface, where each class represents a different operation.

3. Define an invoker class that asks the command to carry out the request.

6. Implementation in Kotlin Programming

// Step 1: Command Interface
interface Command {
    fun execute()
}
// Step 2: Concrete Command Classes
class LightOnCommand(private val light: Light) : Command {
    override fun execute() {
        light.turnOn()
    }
}
class LightOffCommand(private val light: Light) : Command {
    override fun execute() {
        light.turnOff()
    }
}
// Receiver Class
class Light {
    fun turnOn() {
        println("Light is ON")
    }
    fun turnOff() {
        println("Light is OFF")
    }
}
// Step 3: Invoker
class RemoteControl(private val command: Command) {
    fun pressButton() {
        command.execute()
    }
}
// Test the implementation
fun main() {
    val light = Light()
    val lightOnCommand = LightOnCommand(light)
    val lightOffCommand = LightOffCommand(light)
    val remote = RemoteControl(lightOnCommand)
    remote.pressButton()
    val remote2 = RemoteControl(lightOffCommand)
    remote2.pressButton()
}

Output:

Light is ON
Light is OFF

Explanation:

1. The Command interface declares a method named execute.

2. LightOnCommand and LightOffCommand are concrete implementations of the Command interface. They encapsulate the action and the receiver.

3. The RemoteControl class (invoker) allows you to execute a command when its button is pressed.

4. In the main function, a light is turned on and then off using the command pattern.

7. When to use?

Use the Command pattern when:

1. You want to decouple objects that issue commands from objects that perform the command.

2. You need to queue operations, schedule their execution, or execute them remotely.

3. You need support for undoable operations.

Comments