Requirement: We need a tool that simulates a hardware device that communicates via RS232 or TCP/IP to allow us to test our main application which will communicate with the device.
- User loads script
- Parse script into commands
- User runs script
- Execute commands
Script / commands (simplified for discussion):
- Connect RS232 => RS232ConnectCommand
- Connect TCP/IP => TcpIpConnectCommand
- Send data => SendCommand
- Receive data => ReceiveCommand
- Disconnect => DisconnectCommand
All commands implement the ICommand interface. The command runner simply executes a sequence of ICommand implementations sequentially thus ICommand must have an Execute exposure, pseudo code:
- void Execute(ICommunicator context)
The Execute method takes a context argument which allows the command implementations to execute what they need to do. For instance SendCommand will call context.Send, etc.
The problem RS232ConnectCommand and TcpIpConnectCommand needs to instantiate the context to be used by subsequent commands. How do you handle this elegantly?
Solution 1: Change ICommand Execute method to:
- ICommunicator Execute(ICommunicator context)
While it will work it seems like a code smell. All commands now need to return the context which for all commands except the connection ones will be the same context that is passed in.
Solution 2: Create an ICommunicatorWrapper (ICommunicationBroker?) which follows the decorator pattern and decorates ICommunicator. It introduces a new exposure:
- void SetCommunicator(ICommunicator communicator)
And ICommand is changed to use the wrapper:
- void Execute(ICommunicationWrapper context)
Seems like a cleaner solution.
Is this a good design? Am I on the right track?