The entity's involved to implement the command pattern are the Client, Invoker, Command, and Receiver.
The Client will call the functions belonging to the Invoker: setCommand(command), and executeCommand(). The function setCommand(command) sets a variable "command" to the value passed by the function call parameter. The function executeCommand() calls the execute() function of the command previously set.
Each Command class must contain an execute() method called by the Invoker, and a reference the Receiver for that command. The Command's execute() function will call functions belonging to its Receiver.
In our GUI backend, the class MWindowWrapper will serve as both the Client and the Invoker. When command buttons are pressed in the UI, a function attached to that button within MWindowWrapper will call the setCommand() and executeCommand() functions also within MWindowWrapper. The receiver for a command must also be set when the command's constructor is called. MWindowWrapper will contain references to the receiver classes Logic and HealthCheckReq, which will be stored in a list "receivers[]" at index 0 and 1 respectively.
EX:
Attaching a function to a UI button:
self.launchBtn.clicked.connect(self.launchBtn_clicked)
Launch button function definition:
def launchBtn_clicked(self):
self.setCommand(Launch(self.receivers[0]))
self.executeCommand()
Definitions for setCommand() and executeCommand():
def setCommand(self, command):
self.command = command
def executeCommand(self):
self.command.execute()
Task Summary
The first thing we want to do is move all command classes into a single file "Commands.py", including the Command super class. This will save space in our project.
Since we already have created Command classes, each with its own message and execute function, we want to test these Command classes interacting with the other entities of the "command pattern".
On a new branch from GUI/main, create a python file "command_test.py". Inside this new files, create a "MockInvoker" class and a "MockReceiver" class.
MockInvoker should have variables "command" and "receiver", and functions "setCommand(command)" and "executeCommand()".
MockReceiver should have a function "printMessage(message)".
Modify each execute() function of the commands to call receiver.printMessage(self.message).
Inside "if name == "main": " of command_test.py, instantiate the MockInvoker and MockReceiver functions by calling their constructors.
Then for each Command class, instantiate the command by calling the constructor for that command and providing the MockReceiver class as a parameter to the constructor. The Command classes may have to be modified to hold the receiver as a variable. Then call the Invoker functions setCommand(command) and executeCommand().
Do this for each command. When you run "command_test.py", the message belonging to each command should be printed to the console.
Acceptance Criteria
[x] Create new branch from GUI/main and create a file "command_test.py"
[x] Modify Command classes to exist in a single class. Each command class should have a variable "receiver" that is set in the constructor, and an execute() method which calls "self.receiver.printMessage(self.message)".
[x] Create classes MockReceiver and MockInvoker inside "command_test.py" with the necessary methods for the command pattern.
[x] Test the command pattern by creating and invoking each command in "if name == "main": " of command_test.py
[x] Commit your changes, and make a new pull request to merge your branch back to GUI/main
Background
In the GUI backend, the Command, MWindowWrapper, Logic, and HealthCheckReq classes together implement the "Command pattern".
Command pattern overview: https://refactoring.guru/design-patterns/command
The entity's involved to implement the command pattern are the Client, Invoker, Command, and Receiver.
The Client will call the functions belonging to the Invoker: setCommand(command), and executeCommand(). The function setCommand(command) sets a variable "command" to the value passed by the function call parameter. The function executeCommand() calls the execute() function of the command previously set.
Each Command class must contain an execute() method called by the Invoker, and a reference the Receiver for that command. The Command's execute() function will call functions belonging to its Receiver.
In our GUI backend, the class MWindowWrapper will serve as both the Client and the Invoker. When command buttons are pressed in the UI, a function attached to that button within MWindowWrapper will call the setCommand() and executeCommand() functions also within MWindowWrapper. The receiver for a command must also be set when the command's constructor is called. MWindowWrapper will contain references to the receiver classes Logic and HealthCheckReq, which will be stored in a list "receivers[]" at index 0 and 1 respectively.
EX:
Attaching a function to a UI button: self.launchBtn.clicked.connect(self.launchBtn_clicked)
Launch button function definition: def launchBtn_clicked(self): self.setCommand(Launch(self.receivers[0])) self.executeCommand()
Definitions for setCommand() and executeCommand(): def setCommand(self, command): self.command = command def executeCommand(self): self.command.execute()
Task Summary
The first thing we want to do is move all command classes into a single file "Commands.py", including the Command super class. This will save space in our project.
Since we already have created Command classes, each with its own message and execute function, we want to test these Command classes interacting with the other entities of the "command pattern".
On a new branch from GUI/main, create a python file "command_test.py". Inside this new files, create a "MockInvoker" class and a "MockReceiver" class. MockInvoker should have variables "command" and "receiver", and functions "setCommand(command)" and "executeCommand()". MockReceiver should have a function "printMessage(message)". Modify each execute() function of the commands to call receiver.printMessage(self.message).
Inside "if name == "main": " of command_test.py, instantiate the MockInvoker and MockReceiver functions by calling their constructors.
mockInvoker = MockInvoker() mockReceiver = MockReceiver()
Then for each Command class, instantiate the command by calling the constructor for that command and providing the MockReceiver class as a parameter to the constructor. The Command classes may have to be modified to hold the receiver as a variable. Then call the Invoker functions setCommand(command) and executeCommand().
estop = Estop(mockReceiver) mockInvoker.setCommand(estop) mockInvoker.executeCommand()
Do this for each command. When you run "command_test.py", the message belonging to each command should be printed to the console.
Acceptance Criteria