diff --git a/src/main/java/com/smarthome/command/GetStatusCommand.java b/src/main/java/com/smarthome/command/GetStatusCommand.java index 5914e51..779b0e6 100644 --- a/src/main/java/com/smarthome/command/GetStatusCommand.java +++ b/src/main/java/com/smarthome/command/GetStatusCommand.java @@ -2,6 +2,8 @@ import com.smarthome.model.LightState; import com.smarthome.service.LightService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * GetStatusCommand - A Concrete Command to get the current light status. @@ -11,7 +13,11 @@ * * STRICT DECOUPLING: This allows the Controller to get status * without having any direct reference to the LightService. + * + * SPRING BEAN: This command is a Spring-managed bean (@Component) that + * is injected with the LightService (Receiver) dependency. */ +@Component public class GetStatusCommand implements Command { /** @@ -21,9 +27,11 @@ public class GetStatusCommand implements Command { /** * Constructor that receives the Receiver (LightService) as a dependency. + * Spring will inject the LightService bean automatically. * * @param lightService The service that holds the light state */ + @Autowired public GetStatusCommand(LightService lightService) { this.lightService = lightService; } diff --git a/src/main/java/com/smarthome/command/LightOffCommand.java b/src/main/java/com/smarthome/command/LightOffCommand.java index 8d74572..260c586 100644 --- a/src/main/java/com/smarthome/command/LightOffCommand.java +++ b/src/main/java/com/smarthome/command/LightOffCommand.java @@ -2,6 +2,8 @@ import com.smarthome.model.LightState; import com.smarthome.service.LightService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * LightOffCommand - A Concrete Command in the Command Design Pattern. @@ -10,10 +12,14 @@ * It holds a reference to the Receiver (LightService) and delegates * the actual work to it. * - * STRICT DECOUPLING: The Controller (Invoker) doesn't need to know about + * STRICT DECOUPLING: The Controller (Client) doesn't need to know about * the LightService. It only knows about the Command interface. * This command handles all interaction with the Receiver internally. + * + * SPRING BEAN: This command is a Spring-managed bean (@Component) that + * is injected with the LightService (Receiver) dependency. */ +@Component public class LightOffCommand implements Command { /** @@ -23,9 +29,11 @@ public class LightOffCommand implements Command { /** * Constructor that receives the Receiver (LightService) as a dependency. + * Spring will inject the LightService bean automatically. * * @param lightService The service that will perform the actual operation */ + @Autowired public LightOffCommand(LightService lightService) { this.lightService = lightService; } diff --git a/src/main/java/com/smarthome/command/LightOnCommand.java b/src/main/java/com/smarthome/command/LightOnCommand.java index 1ce7247..10485a0 100644 --- a/src/main/java/com/smarthome/command/LightOnCommand.java +++ b/src/main/java/com/smarthome/command/LightOnCommand.java @@ -2,6 +2,8 @@ import com.smarthome.model.LightState; import com.smarthome.service.LightService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * LightOnCommand - A Concrete Command in the Command Design Pattern. @@ -10,10 +12,14 @@ * It holds a reference to the Receiver (LightService) and delegates * the actual work to it. * - * STRICT DECOUPLING: The Controller (Invoker) doesn't need to know about + * STRICT DECOUPLING: The Controller (Client) doesn't need to know about * the LightService. It only knows about the Command interface. * This command handles all interaction with the Receiver internally. + * + * SPRING BEAN: This command is a Spring-managed bean (@Component) that + * is injected with the LightService (Receiver) dependency. */ +@Component public class LightOnCommand implements Command { /** @@ -23,9 +29,11 @@ public class LightOnCommand implements Command { /** * Constructor that receives the Receiver (LightService) as a dependency. + * Spring will inject the LightService bean automatically. * * @param lightService The service that will perform the actual operation */ + @Autowired public LightOnCommand(LightService lightService) { this.lightService = lightService; } diff --git a/src/main/java/com/smarthome/controller/DashboardController.java b/src/main/java/com/smarthome/controller/DashboardController.java index 56811dd..34e9afc 100644 --- a/src/main/java/com/smarthome/controller/DashboardController.java +++ b/src/main/java/com/smarthome/controller/DashboardController.java @@ -1,5 +1,9 @@ package com.smarthome.controller; +import com.smarthome.command.Command; +import com.smarthome.command.GetStatusCommand; +import com.smarthome.command.LightOffCommand; +import com.smarthome.command.LightOnCommand; import com.smarthome.invoker.CommandInvoker; import com.smarthome.model.LightState; import org.springframework.beans.factory.annotation.Autowired; @@ -10,9 +14,10 @@ /** * DashboardController - The Client in the Strict Command Design Pattern. * - * REFACTORED ARCHITECTURE: + * REFACTORED ARCHITECTURE (Per UML Class Diagram): * - The Controller acts as a CLIENT, not an Invoker - * - The Controller delegates command creation and execution to the CommandInvoker + * - The Controller has reference to Command beans (injected by Spring) + * - The Controller delegates command queuing and execution to the CommandInvoker * - The Controller has NO direct dependency on the Receiver (LightService) * - All communication with the Receiver happens through Commands via the Invoker * @@ -21,9 +26,10 @@ * - Returns View names, not raw data * - Uses Spring's Model to pass data to the View * - * EXECUTION FLOW: - * Controller -> Creates Command via Invoker -> Pushes Command to Invoker -> Invoker processes Queue - * -> Command calls Receiver -> Receiver updates Model + * EXECUTION FLOW (Per UML Sequence Diagram): + * Controller -> Sets Command via setCommand() -> Pushes Command via pushCurrentCommand() + * -> Invoker queues Command -> Controller triggers executeCommands() + * -> Invoker processes Queue (FIFO) -> Command calls Receiver -> Returns LightState * * DECOUPLING BENEFITS: * - Controller doesn't know HOW to control the light @@ -35,31 +41,59 @@ public class DashboardController { /** - * The CommandInvoker manages command creation, queue, and execution. - * Controller creates commands via the Invoker and triggers execution. + * The CommandInvoker manages command queue and execution. + * Controller sets commands on the Invoker and triggers execution. */ private final CommandInvoker commandInvoker; + /** + * Command bean reference for getting light status (per UML: -command: Command). + * Injected by Spring as a managed bean. + */ + private final Command getStatusCommand; + + /** + * Command bean reference for turning light ON (per UML: -command: Command). + * Injected by Spring as a managed bean. + */ + private final Command lightOnCommand; + + /** + * Command bean reference for turning light OFF (per UML: -command: Command). + * Injected by Spring as a managed bean. + */ + private final Command lightOffCommand; + /** * Constructor-based dependency injection. - * The Controller only needs the CommandInvoker - it doesn't know about LightService. + * The Controller receives the CommandInvoker and Command beans. + * NOTE: The Controller does NOT receive LightService - strict decoupling. * - * @param commandInvoker The dedicated Invoker for command creation and execution + * @param commandInvoker The dedicated Invoker for command queuing and execution + * @param getStatusCommand The command bean for getting light status + * @param lightOnCommand The command bean for turning light ON + * @param lightOffCommand The command bean for turning light OFF */ @Autowired - public DashboardController(CommandInvoker commandInvoker) { + public DashboardController(CommandInvoker commandInvoker, + GetStatusCommand getStatusCommand, + LightOnCommand lightOnCommand, + LightOffCommand lightOffCommand) { this.commandInvoker = commandInvoker; + this.getStatusCommand = getStatusCommand; + this.lightOnCommand = lightOnCommand; + this.lightOffCommand = lightOffCommand; } /** * Displays the Smart Home Dashboard. * - * REFACTORED COMMAND PATTERN FLOW: + * COMMAND PATTERN FLOW (Per UML Sequence Diagram): * 1. User navigates to /dashboard - * 2. Controller creates a GET_STATUS command via the Invoker - * 3. Controller pushes Command to CommandInvoker - * 4. Controller triggers execution via the Invoker - * 5. Invoker executes Command from queue + * 2. Controller sets the GET_STATUS command via invoker.setCommand() + * 3. Controller pushes Command to queue via invoker.pushCurrentCommand() + * 4. Controller triggers execution via invoker.executeCommands() + * 5. Invoker processes queue (FIFO) and executes Command * 6. Command returns LightState (Model) * 7. Controller adds Model to Spring's Model * 8. Controller returns "dashboard" (View name) @@ -71,9 +105,11 @@ public DashboardController(CommandInvoker commandInvoker) { */ @GetMapping("/dashboard") public String showDashboard(Model model) { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.GET_STATUS); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(getStatusCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) LightState lightState = commandInvoker.executeCommands(); // Add Model to Spring's Model for the View @@ -86,12 +122,12 @@ public String showDashboard(Model model) { /** * Turns ON the light and returns to dashboard. * - * REFACTORED COMMAND PATTERN FLOW: + * COMMAND PATTERN FLOW (Per UML Sequence Diagram): * 1. User clicks "Turn ON" button on View - * 2. Controller creates a LIGHT_ON command via the Invoker - * 3. Controller pushes Command to CommandInvoker - * 4. Controller triggers execution via the Invoker - * 5. Invoker executes Command from queue + * 2. Controller sets the LIGHT_ON command via invoker.setCommand() + * 3. Controller pushes Command to queue via invoker.pushCurrentCommand() + * 4. Controller triggers execution via invoker.executeCommands() + * 5. Invoker processes queue (FIFO) and executes Command * 6. Command delegates to Receiver (internally) * 7. Command returns LightState (Model) * 8. Controller returns "dashboard" (View name) @@ -104,9 +140,11 @@ public String showDashboard(Model model) { */ @GetMapping("/light/on") public String turnLightOn(Model model) { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(lightOnCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) LightState lightState = commandInvoker.executeCommands(); // Add Model to Spring's Model for the View @@ -119,12 +157,12 @@ public String turnLightOn(Model model) { /** * Turns OFF the light and returns to dashboard. * - * REFACTORED COMMAND PATTERN FLOW: + * COMMAND PATTERN FLOW (Per UML Sequence Diagram): * 1. User clicks "Turn OFF" button on View - * 2. Controller creates a LIGHT_OFF command via the Invoker - * 3. Controller pushes Command to CommandInvoker - * 4. Controller triggers execution via the Invoker - * 5. Invoker executes Command from queue + * 2. Controller sets the LIGHT_OFF command via invoker.setCommand() + * 3. Controller pushes Command to queue via invoker.pushCurrentCommand() + * 4. Controller triggers execution via invoker.executeCommands() + * 5. Invoker processes queue (FIFO) and executes Command * 6. Command delegates to Receiver (internally) * 7. Command returns LightState (Model) * 8. Controller returns "dashboard" (View name) @@ -137,9 +175,11 @@ public String turnLightOn(Model model) { */ @GetMapping("/light/off") public String turnLightOff(Model model) { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_OFF); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(lightOffCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) LightState lightState = commandInvoker.executeCommands(); // Add Model to Spring's Model for the View diff --git a/src/main/java/com/smarthome/controller/SmartHomeController.java b/src/main/java/com/smarthome/controller/SmartHomeController.java index 2073eed..7684d0c 100644 --- a/src/main/java/com/smarthome/controller/SmartHomeController.java +++ b/src/main/java/com/smarthome/controller/SmartHomeController.java @@ -1,5 +1,9 @@ package com.smarthome.controller; +import com.smarthome.command.Command; +import com.smarthome.command.GetStatusCommand; +import com.smarthome.command.LightOffCommand; +import com.smarthome.command.LightOnCommand; import com.smarthome.invoker.CommandInvoker; import com.smarthome.model.LightState; import org.springframework.beans.factory.annotation.Autowired; @@ -11,37 +15,63 @@ * SmartHomeController - REST API Client in the Strict Command Design Pattern. * * This REST controller provides API endpoints for controlling the light. - * It follows the same refactored command pattern as DashboardController. + * It follows the same command pattern as DashboardController. * - * REFACTORED ARCHITECTURE: + * REFACTORED ARCHITECTURE (Per UML Class Diagram): * - Controller acts as a CLIENT, not an Invoker - * - Controller delegates command creation and execution to the CommandInvoker - * - Controller has NO direct dependency on LightService (only CommandInvoker does) + * - Controller has reference to Command beans (injected by Spring) + * - Controller delegates command queuing and execution to the CommandInvoker + * - Controller has NO direct dependency on LightService * - All communication with Receiver happens through Commands via the Invoker * - * EXECUTION FLOW: - * Controller -> Creates Command via Invoker -> Pushes Command to Invoker -> Invoker processes Queue - * -> Command calls Receiver -> Receiver updates Model + * EXECUTION FLOW (Per UML Sequence Diagram): + * Controller -> Sets Command via setCommand() -> Pushes Command via pushCurrentCommand() + * -> Invoker queues Command -> Controller triggers executeCommands() + * -> Invoker processes Queue (FIFO) -> Command calls Receiver -> Returns LightState */ @RestController @RequestMapping("/api/light") public class SmartHomeController { /** - * The CommandInvoker manages command creation, queue, and execution. - * Controller creates commands via the Invoker and triggers execution. + * The CommandInvoker manages command queue and execution. + * Controller sets commands on the Invoker and triggers execution. */ private final CommandInvoker commandInvoker; /** - * Constructor - Controller only needs CommandInvoker. - * Controller NEVER uses LightService directly. + * Command bean reference for getting light status. + */ + private final Command getStatusCommand; + + /** + * Command bean reference for turning light ON. + */ + private final Command lightOnCommand; + + /** + * Command bean reference for turning light OFF. + */ + private final Command lightOffCommand; + + /** + * Constructor - Controller receives CommandInvoker and Command beans. + * Controller NEVER receives LightService directly. * - * @param commandInvoker The dedicated Invoker for command creation and execution + * @param commandInvoker The dedicated Invoker for command queuing and execution + * @param getStatusCommand The command bean for getting light status + * @param lightOnCommand The command bean for turning light ON + * @param lightOffCommand The command bean for turning light OFF */ @Autowired - public SmartHomeController(CommandInvoker commandInvoker) { + public SmartHomeController(CommandInvoker commandInvoker, + GetStatusCommand getStatusCommand, + LightOnCommand lightOnCommand, + LightOffCommand lightOffCommand) { this.commandInvoker = commandInvoker; + this.getStatusCommand = getStatusCommand; + this.lightOnCommand = lightOnCommand; + this.lightOffCommand = lightOffCommand; } /** @@ -51,9 +81,11 @@ public SmartHomeController(CommandInvoker commandInvoker) { */ @GetMapping("/on") public LightState turnLightOn() { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(lightOnCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) return commandInvoker.executeCommands(); } @@ -64,9 +96,11 @@ public LightState turnLightOn() { */ @GetMapping("/off") public LightState turnLightOff() { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_OFF); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(lightOffCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) return commandInvoker.executeCommands(); } @@ -77,9 +111,11 @@ public LightState turnLightOff() { */ @GetMapping("/status") public LightState getLightStatus() { - // Create command via Invoker, push, and execute - commandInvoker.createCommand(CommandInvoker.CommandType.GET_STATUS); + // Set command via Invoker (per UML: setCommand) + commandInvoker.setCommand(getStatusCommand); + // Push command to queue (per UML: pushCurrentCommand) commandInvoker.pushCurrentCommand(); + // Execute commands and get result (per UML: executeCommands) return commandInvoker.executeCommands(); } } diff --git a/src/main/java/com/smarthome/invoker/CommandInvoker.java b/src/main/java/com/smarthome/invoker/CommandInvoker.java index 0c6e659..bb3b9f3 100644 --- a/src/main/java/com/smarthome/invoker/CommandInvoker.java +++ b/src/main/java/com/smarthome/invoker/CommandInvoker.java @@ -1,12 +1,7 @@ package com.smarthome.invoker; import com.smarthome.command.Command; -import com.smarthome.command.LightOnCommand; -import com.smarthome.command.LightOffCommand; -import com.smarthome.command.GetStatusCommand; import com.smarthome.model.LightState; -import com.smarthome.service.LightService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.LinkedList; @@ -20,78 +15,51 @@ * by extracting the Invoker logic from the Controller. * * STRICT COMMAND PATTERN IMPLEMENTATION: - * - Maintains a Queue (FIFO) of commands - * - Connects to the Receiver (LightService) to create commands - * - Allows creating a command by type before pushing it to the queue - * - Exposes a method to push (add) commands to the queue - * - Has a mechanism to execute pending commands sequentially - * - Controller (Client) creates and pushes commands here; Invoker executes them + * - Maintains a Queue (FIFO) using LinkedList + * - Allows setting a command reference via setCommand() + * - Exposes pushCurrentCommand() to add the current command to the queue + * - Exposes push() to directly add commands to the queue + * - executeCommands() processes queue in FIFO order and returns last result + * - Controller (Client) sets/pushes commands; Invoker queues and executes them * * EXECUTION FLOW: - * Controller -> Creates Command via Invoker -> Pushes Command to Invoker -> Invoker processes Queue - * -> Command calls Receiver -> Receiver updates Model + * Controller -> Sets Command via setCommand() -> Pushes Command via pushCurrentCommand() + * -> Invoker queues Command -> Controller triggers executeCommands() + * -> Invoker processes Queue (FIFO) -> Command calls Receiver -> Returns LightState */ @Component public class CommandInvoker { - /** - * Enum defining the types of commands that can be created. - */ - public enum CommandType { - LIGHT_ON, - LIGHT_OFF, - GET_STATUS - } - /** * FIFO queue to hold pending commands. - * Commands are executed in the order they are added. + * Commands are executed in the order they are added (First-In, First-Out). */ private final Queue commandQueue; /** - * The Receiver (LightService) used to create commands. - */ - private final LightService lightService; - - /** - * The currently created command that can be pushed to the queue. - * This allows creating a command before pushing it. + * The currently set command that can be pushed to the queue. + * This allows setting a command before pushing it to the queue. */ private Command command; /** - * Constructor with LightService dependency injection. - * The Invoker connects to the Receiver to create commands. - * - * @param lightService The Receiver used to create commands + * Default constructor. + * Initializes the command queue as a LinkedList for FIFO behavior. */ - @Autowired - public CommandInvoker(LightService lightService) { + public CommandInvoker() { this.commandQueue = new LinkedList<>(); - this.lightService = lightService; } /** - * Creates a command of the specified type using the Receiver. + * Sets the current command reference. * This command can then be pushed to the queue using pushCurrentCommand(). * - * @param commandType The type of command to create + * Per UML: setCommand(command: Command): void + * + * @param command The command to set as the current command */ - public void createCommand(CommandType commandType) { - switch (commandType) { - case LIGHT_ON: - this.command = new LightOnCommand(lightService); - break; - case LIGHT_OFF: - this.command = new LightOffCommand(lightService); - break; - case GET_STATUS: - this.command = new GetStatusCommand(lightService); - break; - default: - throw new IllegalArgumentException("Unknown command type: " + commandType); - } + public void setCommand(Command command) { + this.command = command; } /** @@ -104,14 +72,16 @@ public Command getCommand() { } /** - * Pushes the currently created command to the queue. - * The command must be created using createCommand() before calling this method. + * Pushes the currently set command to the queue. + * The command must be set using setCommand() before calling this method. * - * @throws IllegalStateException if no command has been created + * Per UML: pushCurrentCommand(): void - Adds the currently set command to the queue. + * + * @throws IllegalStateException if no command has been set */ public void pushCurrentCommand() { if (this.command == null) { - throw new IllegalStateException("No command has been created. Call createCommand() first."); + throw new IllegalStateException("No command has been set. Call setCommand() first."); } commandQueue.add(this.command); } @@ -130,16 +100,33 @@ public void push(Command command) { /** * Executes all pending commands in the queue sequentially (FIFO order). - * Returns the result of the last executed command. + * + * QUEUE PROCESSING LOGIC (FIFO - First In, First Out): + * 1. Check if the queue has pending commands + * 2. Poll (remove) the first command from the queue + * 3. Execute the command by calling its execute() method + * 4. Store the result (LightState) from the command + * 5. Repeat steps 1-4 until the queue is empty + * 6. Return the LightState from the LAST executed command + * + * NOTE: The queue is automatically cleared as each command is polled and executed. + * This ensures commands are only executed once. * * @return LightState from the last executed command, or null if queue was empty */ public LightState executeCommands() { + // Track the result of the last executed command LightState lastState = null; + + // Process the queue in FIFO order - poll removes and returns the head of the queue while (!commandQueue.isEmpty()) { + // Poll the next command (FIFO - first added is first executed) Command command = commandQueue.poll(); + // Execute the command and store the result lastState = command.execute(); } + + // Return the result of the last command (for Controller to update the View) return lastState; } diff --git a/src/test/java/com/smarthome/CommandInvokerTest.java b/src/test/java/com/smarthome/CommandInvokerTest.java index e354cb0..a0b7ada 100644 --- a/src/test/java/com/smarthome/CommandInvokerTest.java +++ b/src/test/java/com/smarthome/CommandInvokerTest.java @@ -18,7 +18,7 @@ * * These tests verify: * 1. CommandInvoker maintains a FIFO queue of commands - * 2. Commands can be created and pushed to the queue + * 2. Commands can be set and pushed to the queue * 3. Commands are executed sequentially in FIFO order * 4. ExecuteCommands returns the result of the last command * 5. Queue management (size, clear) works correctly @@ -31,7 +31,7 @@ class CommandInvokerTest { @BeforeEach void setUp() { lightService = new LightService(); - commandInvoker = new CommandInvoker(lightService); + commandInvoker = new CommandInvoker(); } // ==================== Queue Management Tests ==================== @@ -233,30 +233,33 @@ void multipleCommandSequences_shouldWorkCorrectly() { assertTrue(state3.isOn()); } - // ==================== CreateCommand Tests ==================== + // ==================== SetCommand Tests ==================== @Test - @DisplayName("CreateCommand LIGHT_ON should create LightOnCommand") - void createCommand_lightOn_shouldCreateLightOnCommand() { - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + @DisplayName("SetCommand with LightOnCommand should set command reference") + void setCommand_lightOn_shouldSetLightOnCommand() { + Command lightOnCommand = new LightOnCommand(lightService); + commandInvoker.setCommand(lightOnCommand); assertNotNull(commandInvoker.getCommand()); assertTrue(commandInvoker.getCommand() instanceof LightOnCommand); } @Test - @DisplayName("CreateCommand LIGHT_OFF should create LightOffCommand") - void createCommand_lightOff_shouldCreateLightOffCommand() { - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_OFF); + @DisplayName("SetCommand with LightOffCommand should set command reference") + void setCommand_lightOff_shouldSetLightOffCommand() { + Command lightOffCommand = new LightOffCommand(lightService); + commandInvoker.setCommand(lightOffCommand); assertNotNull(commandInvoker.getCommand()); assertTrue(commandInvoker.getCommand() instanceof LightOffCommand); } @Test - @DisplayName("CreateCommand GET_STATUS should create GetStatusCommand") - void createCommand_getStatus_shouldCreateGetStatusCommand() { - commandInvoker.createCommand(CommandInvoker.CommandType.GET_STATUS); + @DisplayName("SetCommand with GetStatusCommand should set command reference") + void setCommand_getStatus_shouldSetGetStatusCommand() { + Command getStatusCommand = new GetStatusCommand(lightService); + commandInvoker.setCommand(getStatusCommand); assertNotNull(commandInvoker.getCommand()); assertTrue(commandInvoker.getCommand() instanceof GetStatusCommand); @@ -269,9 +272,10 @@ void getCommand_initially_shouldReturnNull() { } @Test - @DisplayName("PushCurrentCommand should add created command to queue") - void pushCurrentCommand_shouldAddCreatedCommandToQueue() { - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + @DisplayName("PushCurrentCommand should add set command to queue") + void pushCurrentCommand_shouldAddSetCommandToQueue() { + Command lightOnCommand = new LightOnCommand(lightService); + commandInvoker.setCommand(lightOnCommand); commandInvoker.pushCurrentCommand(); @@ -279,15 +283,16 @@ void pushCurrentCommand_shouldAddCreatedCommandToQueue() { } @Test - @DisplayName("PushCurrentCommand without createCommand should throw exception") - void pushCurrentCommand_withoutCreateCommand_shouldThrowException() { + @DisplayName("PushCurrentCommand without setCommand should throw exception") + void pushCurrentCommand_withoutSetCommand_shouldThrowException() { assertThrows(IllegalStateException.class, () -> commandInvoker.pushCurrentCommand()); } @Test - @DisplayName("CreateCommand then pushCurrentCommand then execute should work") - void createCommand_pushCurrentCommand_execute_shouldWork() { - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + @DisplayName("SetCommand then pushCurrentCommand then execute should work") + void setCommand_pushCurrentCommand_execute_shouldWork() { + Command lightOnCommand = new LightOnCommand(lightService); + commandInvoker.setCommand(lightOnCommand); commandInvoker.pushCurrentCommand(); LightState result = commandInvoker.executeCommands(); @@ -297,14 +302,14 @@ void createCommand_pushCurrentCommand_execute_shouldWork() { } @Test - @DisplayName("Multiple createCommand and pushCurrentCommand should work correctly") - void multipleCreateCommandAndPush_shouldWorkCorrectly() { - // Create and push ON command - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + @DisplayName("Multiple setCommand and pushCurrentCommand should work correctly") + void multipleSetCommandAndPush_shouldWorkCorrectly() { + // Set and push ON command + commandInvoker.setCommand(new LightOnCommand(lightService)); commandInvoker.pushCurrentCommand(); - // Create and push OFF command (overwrites the created command reference) - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_OFF); + // Set and push OFF command (overwrites the set command reference) + commandInvoker.setCommand(new LightOffCommand(lightService)); commandInvoker.pushCurrentCommand(); // Execute both @@ -317,29 +322,29 @@ void multipleCreateCommandAndPush_shouldWorkCorrectly() { } @Test - @DisplayName("CreateCommand connects to Receiver and creates functional commands") - void createCommand_connectsToReceiver_createsWorkingCommands() { + @DisplayName("SetCommand with commands connected to Receiver works correctly") + void setCommand_withReceiverConnection_createsWorkingCommands() { // Initial state assertFalse(lightService.isLightOn()); - // Create LIGHT_ON command via Invoker - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_ON); + // Set LIGHT_ON command and execute + commandInvoker.setCommand(new LightOnCommand(lightService)); commandInvoker.pushCurrentCommand(); LightState onState = commandInvoker.executeCommands(); assertTrue(onState.isOn()); assertTrue(lightService.isLightOn()); - // Create LIGHT_OFF command via Invoker - commandInvoker.createCommand(CommandInvoker.CommandType.LIGHT_OFF); + // Set LIGHT_OFF command and execute + commandInvoker.setCommand(new LightOffCommand(lightService)); commandInvoker.pushCurrentCommand(); LightState offState = commandInvoker.executeCommands(); assertFalse(offState.isOn()); assertFalse(lightService.isLightOn()); - // Create GET_STATUS command via Invoker - commandInvoker.createCommand(CommandInvoker.CommandType.GET_STATUS); + // Set GET_STATUS command and execute + commandInvoker.setCommand(new GetStatusCommand(lightService)); commandInvoker.pushCurrentCommand(); LightState statusState = commandInvoker.executeCommands(); diff --git a/src/test/java/com/smarthome/DashboardControllerTest.java b/src/test/java/com/smarthome/DashboardControllerTest.java index 862afc7..f5dc6f8 100644 --- a/src/test/java/com/smarthome/DashboardControllerTest.java +++ b/src/test/java/com/smarthome/DashboardControllerTest.java @@ -1,5 +1,8 @@ package com.smarthome; +import com.smarthome.command.GetStatusCommand; +import com.smarthome.command.LightOffCommand; +import com.smarthome.command.LightOnCommand; import com.smarthome.controller.DashboardController; import com.smarthome.invoker.CommandInvoker; import com.smarthome.service.LightService; @@ -20,13 +23,13 @@ * * These tests verify that the MVC flow works correctly: * - Controller receives requests - * - Controller pushes commands to the CommandInvoker - * - Controller triggers execution via the Invoker + * - Controller sets commands on the CommandInvoker + * - Controller pushes commands and triggers execution via the Invoker * - Controller updates the Model * - Controller returns the correct View name */ @WebMvcTest(DashboardController.class) -@Import(CommandInvoker.class) +@Import({CommandInvoker.class, LightOnCommand.class, LightOffCommand.class, GetStatusCommand.class}) class DashboardControllerTest { @Autowired diff --git a/src/test/java/com/smarthome/SmartHomeControllerTest.java b/src/test/java/com/smarthome/SmartHomeControllerTest.java index 3e88759..302afa8 100644 --- a/src/test/java/com/smarthome/SmartHomeControllerTest.java +++ b/src/test/java/com/smarthome/SmartHomeControllerTest.java @@ -1,5 +1,8 @@ package com.smarthome; +import com.smarthome.command.GetStatusCommand; +import com.smarthome.command.LightOffCommand; +import com.smarthome.command.LightOnCommand; import com.smarthome.controller.SmartHomeController; import com.smarthome.invoker.CommandInvoker; import com.smarthome.service.LightService; @@ -24,7 +27,7 @@ * the Strict Command Pattern implementation. */ @WebMvcTest(SmartHomeController.class) -@Import(CommandInvoker.class) +@Import({CommandInvoker.class, LightOnCommand.class, LightOffCommand.class, GetStatusCommand.class}) class SmartHomeControllerTest { @Autowired