The Command Design Pattern
is a Behavioural Design Pattern
and comes under Gang Of Four Design Pattern
Command Design Pattern Hides or Encapsulate a request as a command and pass on, the corresponding object will execute hence following the Principle of Separation of Concerns
.
The Command Design Pattern decouples Command Invoking Object from the Command Consuming Object hence is also known as Producer-Consumer Pattern.
Adding a new Command doesn't require existing code modification ie close for modification, but a new Command can always be added hence following the Open/closed principle.
Some real-world examples of Command Design Patterns are
- A restaurant waiter writes the order on a piece of paper or commands to execute and passes it to the kitchen, the chef prepares the dish and passes it to the queue, and another waiter picks the order and serves it dinner.
- A modern computer supports multiple types of files. the open file command had all the required information, the respective application will open the file.
package org.wesome.design.patterns;
public interface Order {
String processOrder();
}
package org.wesome.design.patterns;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Apple {
private final String name;
private final int quantity;
public String buyApple() {
return "buy " + quantity + " kg of " + name + " apple";
}
public String sellSell() {
return "sell " + quantity + " kg of " + name + " apple";
}
}
package org.wesome.design.patterns;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Shop {
private final List<Order> orderList = new ArrayList<>();
public void takeOrder(Order order) {
orderList.add(order);
}
public List<String> placeOrders() {
List<String> steps;
steps = orderList.stream().map(Order::processOrder).collect(Collectors.toList());
orderList.clear();
return steps;
}
}
package org.wesome.design.patterns;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class BuyApple implements Order {
private final Apple apple;
public String processOrder() {
return apple.buyApple();
}
}
package org.wesome.design.patterns;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class SellApple implements Order {
private final Apple apple;
public String processOrder() {
return apple.sellSell();
}
}
package org.wesome.design.patterns;
public class Command {
public static void main(String[] args) {
BuyApple buyAppleOrder = new BuyApple(new Apple("Macintosh", 10));
SellApple sellAppleOrder = new SellApple(new Apple("Fuji", 50));
Shop shop = new Shop();
shop.takeOrder(buyAppleOrder);
shop.takeOrder(sellAppleOrder);
shop.placeOrders().forEach(System.out::println);
}
}
package org.wesome.design.patterns;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CommandTest {
@Test
void testBuyCommand() {
BuyApple buyAppleOrder = new BuyApple(new Apple("Macintosh", 10));
Shop shop = new Shop();
shop.takeOrder(buyAppleOrder);
List<String> actualCommand = shop.placeOrders();
List<String> expectedCommand = Collections.singletonList("buy 10 kg of Macintosh apple");
Assertions.assertEquals(expectedCommand, actualCommand);
}
@Test
void testSellCommand() {
SellApple sellAppleOrder = new SellApple(new Apple("Fuji", 50));
Shop shop = new Shop();
shop.takeOrder(sellAppleOrder);
List<String> actualCommand = shop.placeOrders();
List<String> expectedCommand = Collections.singletonList("sell 50 kg of Fuji apple");
Assertions.assertEquals(expectedCommand, actualCommand);
}
@Test
void testBuySellCommand() {
BuyApple buyAppleOrder = new BuyApple(new Apple("Macintosh", 10));
SellApple sellAppleOrder = new SellApple(new Apple("Fuji", 50));
Shop shop = new Shop();
shop.takeOrder(buyAppleOrder);
shop.takeOrder(sellAppleOrder);
List<String> actualCommand = shop.placeOrders();
List<String> expectedCommand = Arrays.asList("buy 10 kg of Macintosh apple", "sell 50 kg of Fuji apple");
Assertions.assertEquals(expectedCommand, actualCommand);
}
}
plugins {
id 'java'
id "io.freefair.lombok" version "6.2.0"
}
group = 'org.wesome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.junit.jupiter:junit-jupiter:5.6.2'
}
test {
useJUnitPlatform()
}