Sunday, June 20, 2021

Behavioral Design Pattern - Command Pattern

 Command Design Pattern

So command design pattern is a behavioral pattern that lets you encapsulate. Each request is an object. Of curse, there are more reasons to implement that we will look into those reasons.

Why you would choose the command pattern? 

because it encapsulates. Each request is an object. If you have dealt with or are going to work with a large system, you'll quickly find that the business logic and functions inside that system can be very complex to maintain a debug if they're all just added in one file.

Another key reason for choosing this pattern is that each call back as a request is now object-oriented instead of just another method added insight of that growing class. Maintainability is also increased because the sender is decoupled from the processor. This will enable the system to be more flexible and grow over time, oftentimes, but not the only reason. You will use a command to add undo functionality to your application. The entire request should be contained within the command and then could be rolled back. 

 For Example, Runnable Pattern is a great example of a command Design Pattern. the design of the command is a little different than some of the other patterns and is sometimes argued that it breaks the principles of, oh design because there is an object per command, A command is a verb, and objects usually aren't verbs, but rather the methods inside them. But people have seemed to relax their view on this. The main contract of the command is the command interface, all implementations of actions or commands inside the framework will implement this interface and in its simplest form, just contains an execute method. This method is where all of the action is performed. In the case of an undue feature, the interface will also contain a UN execute or undue method. But this isn't required to adhere to the principles of this pattern. Advanced implementations of this pattern make use of reflection to completely decoupled the client from the receiver or processor using a callback. 

Most examples you see, though, are simpler than this version, and we're going to look at various examples is to see how to best exercise this action and implement it in your day-to-day use.


Code : Example -1 

package command;

public class CommandPattern {

public static void main(String[] args) {
Task t1 = new Task(10, 12); // encapsulates request
Task t2 = new Task(11, 13);

Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);

thread1.start();//invoker
thread2.start();
}
}

class Task implements Runnable {
int num1;
int num2;

public Task(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}

@Override
public void run() { // executor
System.out.println(num1 * num2); // receiver
}
}

Example -2 :

package command;

import java.util.ArrayList;
import java.util.List;

// client
public class CommandPatternExercise {

public static void main(String args[]) {
Light bedroomLight = new Light();
Light kitchenLight = new Light();
Switch lightSwitch = new Switch();

Command toggleCommand = new ToggleCommand(bedroomLight);
lightSwitch.storeAndExecute(toggleCommand);
// lightSwitch.storeAndExecute(toggleCommand);
// lightSwitch.storeAndExecute(toggleCommand);
// lightSwitch.storeAndExecute(toggleCommand);
List<Light> lights = new ArrayList<>();
lights.add(bedroomLight);
lights.add(kitchenLight);

Command alllightsCommand = new AllLightsCommand(lights);
lightSwitch.storeAndExecute(alllightsCommand);

}
}
package command;

// receiver
public class Light {

private boolean isOn = false;

public boolean isOn() {
return isOn;
}

public void toggle() {
if (isOn) {
off();
isOn = false;
} else {
on();
isOn = true;
}
}

private void on() {
System.out.println("Light switched on.");
}

private void off() {
System.out.println("Light switched off.");
}
}

  package command;


//invoker
public class Switch {

public void storeAndExecute(Command command) {
command.execute();
}
}
package command;

public class ToggleCommand implements Command {

private Light light;

public ToggleCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.toggle();
}

} 

Output :


Light switched on.

Light switched off.

So we can implement this design pattern in our real-time project and can extract lots of benefits from it. I learn this pattern 10 years ago Since I am using it from time to time in my projects.

What are some of the pitfalls of a command? 

It's typically used with other patterns to be more mature. The dependence on other patterns isn't necessarily a bad thing. It just requires more knowledge on the developer's part. I also often see people struggle with the use of multiple commands. Frequently, I see people make the mistake of duplicating logic in another command. A better way to do this is either the use of a composite pattern as we demonstrated or commands. Combined with the chain of responsibility pattern for undo functionality, you may want to look at it using the memento pattern to handle state. If you're tracking objects that need to store history, you may need to also look at the prototype pattern for creating copies of commands to store on a list to get a better idea. When we shouldn't or shouldn't use this pattern.

to contrast the command pattern. Let's compare it with the strategy. The command is structured around an object per command or per request. The class contains essentially, what we're trying to do. It also encapsulates CE in the entire action. The command object on Lee deals with this one exact scenario. Thes strategy, on the other hand, is similar to the command in that it is an object per request, with the focus on this pattern being per strategy different than the command. Though the strategy focuses on the how rather than the what. Instead of encapsulating the action, it encapsulates the algorithm. The structure of these patterns is very similar, though with just some slight variations.

That's it.




1 comment:

Anonymous said...

Very nice article and well described.