DEV Community

Oluwasanmi Aderibigbe
Oluwasanmi Aderibigbe

Posted on • Edited on

1

Head First Design Pattern: 5 of 10

I just learnt my fifth design from the Head First Design Pattern book. Today, I learnt about the Command pattern.

According to Head First Design Patterns, the Command pattern is a pattern that encapsulate a request as an object, thereby letting you parameterise other object with different requests, queue and also undo requests.

The command pattern works by decoupling by the object making the request(invoker) and the object that knows how to perform the request. It does this by encapsulating actions into command objects. The command object houses the receiver(which essentially the object performing the action) and it's actions.

The first step is implementing is defining a command interface. This interface defines an method called execute.
The second is creating command objects that implement the command interface.
The third is is creating the invoker class, SmartHomeApp. SmartHomeApp has no knowledge of the actions being performed anytime OnButtonTapped and offButtonTapped.

The code below is an example of the command pattern.

interface Command {
    fun execute(): Unit
}

class TurnOnLightsCommand : Command {
    override fun execute() {
        print("Light turned on")
    }
}

class TurnOffLightsCommand : Command {
    override fun execute() {
        print("Light turned off")
    }
}

class TurnOnTVCommand : Command {
    override fun execute() {
        print("TV turned on")
    }
}

class TurnOffTVCommand : Command {
    override fun execute() {
        print("TV turned off")
    }
}

interface Command {
    fun execute(): Unit
}

class TurnOnLightsCommand : Command {
    override fun execute() {
        println("Light turned on")
    }
}

class TurnOffLightsCommand : Command {
    override fun execute() {
        println("Light turned off")
    }
}

class TurnOnTVCommand : Command {
    override fun execute() {
        println("TV turned on")
    }
}

class TurnOffTVCommand : Command {
    override fun execute() {
        println("TV turned off")
    }
}


class SmartHomeApp {
    private val onCommands = mutableListOf<Command>()
    private val offCommands = mutableListOf<Command>()

    fun setCommand(slot: Int, onCommand: Command, offCommand: Command) {
        onCommands.add(slot, onCommand)
        offCommands.add(slot, offCommand)
    }

    fun onButtonTapped(slot: Int) {
        onCommands[slot].execute()
    }

    fun offButtonTapped(slot: Int) {
        offCommands[slot].execute()
    }
}

fun main() {
    val smartHomeApp = SmartHomeApp()

    smartHomeApp.setCommand(0, TurnOnLightsCommand(), TurnOffLightsCommand())
    smartHomeApp.setCommand(1, TurnOnTVCommand(), TurnOffTVCommand())

    smartHomeApp.onButtonTapped(0)
    smartHomeApp.onButtonTapped(1)

}
Enter fullscreen mode Exit fullscreen mode

The command pattern can be used to implement really cool functionalities like undo, redo actions, performing a sequence of commands(Macros). It also allows you to queue and delay the execution of an action after request was made. With the command pattern you can also implement complex logging and state restoration logic.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay