Command Pattern

Hyung Jun·2020년 12월 3일
0

Design Pattern

목록 보기
2/10
post-thumbnail

This article is lecture note from "Head First Design Patterns" by Elisabeth Freeman and Kathy Sierra and CS course from Kookmin by Inkyu Kim

Definition

The Command Pattern encapsulates a request as an object, thereby letting you parameterise other objects with different requests, queue, or log requests, and support undoable operations.

Command decouples the object that invokes the operation from the one that knows how to perform it. To acheive this seperation, we need to design abstract base class that maps a reciever(an object) with an action(a pointer to a member function). The base class contains an execute method that simply calls the action on the reciever.

Structure

First of all, the sender class (whici is named Invoker in the image) is responsible for initiating request.
This class must have a field for storing a reference to a Command object(interface). The sender triggers that "command" instead of sending the request to the Reciever. Note that the sender class does not have a responsibility for initiating command class.
The command interface usually declares just a single method for executing the command.
Concrete commands (which are named Command1 and Command2) implement various kinds of requests. A concrete command isn't supposed to perform the work on its own, but rather to pass the call to one of its receiver(logic objects). The Receiver is a parameter in the concrete command method.
The Receiver class contains some logic. Most commands only handle the details of how a request is passed to the receiver, while the receiver does the actual work itself.

Source code

Example code : Remote Control API

<Command.java>

public interface Command {
	public void execute();
}

<LightOnCommand.java>

public class LightOnCommand implements Command {
	Light light;
  
	public LightOnCommand(Light light) {
		this.light = light;
	}
 
	public void execute() {
		light.on();
	}
}

We can see the constructor is passed the specific light that this command is going to control. When the execute method gets called, it is the light object that is going to be the receiver of the request.

<SimpleRemoteControl.java>

public class SimpleRemoteControl {
	Command slot;
 
	public SimpleRemoteControl() {}
 
	public void setCommand(Command command) {
		slot = command;
	}
 
	public void buttonWasPressed() {
		slot.execute();
	}
}

There is one slot to hold Command, which will control one device. The setCommand method is a method for setting the command which is the slot is going to control. If the client want to change the behaviour of the command, it could be change anytime(very dynamic).

<RemoteControlTest.java>

public class RemoteControlTest {
	public static void main(String[] args) {
		SimpleRemoteControl remote = new SimpleRemoteControl();
		Light light = new Light();
		GarageDoor garageDoor = new GarageDoor();
		LightOnCommand lightOn = new LightOnCommand(light);
		GarageDoorOpenCommand garageOpen = 
		    new GarageDoorOpenCommand(garageDoor);
 
		remote.setCommand(lightOn);
		remote.buttonWasPressed();
		remote.setCommand(garageOpen);
		remote.buttonWasPressed();
    }
	
}

This is the client in the Command Pattern-speak.
The remote is our Invoker. It will be passed a command object that can be used to make a request. The light and garageDoor are the objects which are the receivers of the requests.

Why is it good?🧐

By designing Command Pattern , we can separate classes that invoke operations from the classes that perform these operations. So it can acheive Single Responsibility Principle.
Furthermore, it can fulfil the Open-Closed Principle. We can easily introduce new commands into the app without breaking existing code.
Functionally we can build our program is capable of doing redo/undo, implementing deferred execution of operations and assembling a set of simple commands into a complex one.

profile
Keep Learning👨🏻‍💻

0개의 댓글