Several years ago, I consulted for a large firm that made photocopiers. I was helping one of its development teams with the design and implementation of the embedded real-time software that drove the inner workings of a new copier. We stumbled on the idea of using the COMMAND pattern to control the hardware devices. We created a hierarchy that looked something like Figure 21-2. Figure 21-2. Some simple commands for the copier software
The role of these classes should be obvious. Call Execute() on a RelayOnCommand turns on a relay. Calling Execute() on a MotorOffCommand turns off a motor. The address of the motor or relay is passed into the object as an argument to its constructor. With this structure in place, we could now pass Command objects around the system and Execute() them without knowing precisely what kind of Command they represented. This led to some interesting simplifications. The system was event driven. Relays opened or closed, motors started or stopped, and clutches engaged or disengaged, based on certain events that took place in the system. Many of those events were detected by sensors. For example, when an optical sensor determined that a sheet of paper had reached a certain point in the paper path, we'd need to engage a certain clutch. We were able to implement this by simply binding the appropriate ClutchOnCommand to the object that controlled that particular optical sensor. See Figure 21-3. Figure 21-3. A command driven by a sensor
This simple structure has an enormous advantage. The Sensor has no idea what it is doing. Whenever it detects an event, it simply calls Execute() on the Command that it is bound to. This means that the Sensors don't have to know about individual clutches or relays. They don't have to know the mechanical structure of the paper path. Their function becomes remarkably simple. The complexity of determining which relays to close when certain sensors declare events has moved to an initialization function. At some point during the initialization of the system, each Sensor is bound to an appropriate Command. This puts all the logical interconnections between the sensors and commandsthe wiringin one place and gets it out of the main body of the system. Indeed, it would be possible to create a simple text file that described which Sensors were bound to which Commands. The initialization program could read this file and build the system appropriately. Thus, the wiring of the system could be determined completely outside the program and could be adjusted without recompilation. By encapsulating the notion of a command, this pattern allowed us to decouple the logical interconnections of the system from the devices that were being connected. This was a huge benefit.
|