Mode Management Design Pattern
Intent
This design pattern addresses the problem of endowing components with mode-dependent behaviour. It separates the implementation of the mode-dependent behaviour from the implementation of the logic required to decide mode switches.
Based On
This is pattern is essentially identical to the mode management pattern of the AOCS Framework (see also: A. Pasetti, Embedded Control Systems and Software Frameworks, Springer-Verlag, 2002).
Motivation
Current on-board applications are based on the concept of operational mode. The operational mode changes in response to changes in the operational environment of the application. The operational mode however is typically seen as an attribute of the on-board application as a whole. This typically requires a single "mode manager" component which is responsible for maintaining the system mode. The mode manager might also be responsible for ensuring that each component behaves in a manner that is consistent with the current mode. This component acts as a centralized coordinator of component behaviour. As such, it normally requires a rather detailed understanding of how each component is constructed and of what its internal state is. This approach therefore weakens behaviour encapsulation.
In an alternative variant of this centralized mode management architecture, the mode manager acts as a client for other components that periodically sample it to ask what the current mode is and use this information to tune their behaviour. Or, equivalently, a registration mechanism could be used based on the classical observer pattern where the application component register with the centralized mode manager and are notified whenever there is a mode change. The drawback of these architectures is that different components may need different sets of modes and a centralized mode manager needs to keep track of all of them which again weakens data encapsulation and component decoupling. Once one decides to move towards a component-based approach, a more appropriate architecture is to make operational mode an attribute of individual components. A mode-dependent component then becomes a component that, depending on operational conditions, needs to select a particular implementation of one or more strategies. As an example consider an attitude controller component in a satellite control system. This component is responsible for implementing the attitude control algorithm and might have two modes: low accuracy control, and high accuracy control. In low accuracy mode, attitude information is provided by a low-accuracy sensor, for instance a coarse sun sensor (CSS), and is processed by a low-accuracy algorithm, for instance a proportional-integral (PI) controller. In high-accuracy mode instead, a high accuracy sensor, for instance a fine sun sensor (FSS), and a high accuracy control algorithm, for instance a PI controller with Kalman filtering (KF), are used. In this case, the controller component (the mode-dependent component) has two strategies (the sensor and the control algorithm) and each strategy has two implementations (the CSS and the FSS for the sensor strategy, and the PI and PI+KF for the control algorithm strategy). During normal operation, the satellite decides which strategy to use based on the size of the control error.The advantage of this approach is that it allows the selection of the operational modes and of their associated strategies to be tailored to the needs of each component. Its potential disadvantage is that it complicates the problem of separating the problem of designing and implementing the strategies separate from the problem of designing and implementing the logic that controls the operational mode transitions. There is a risk that each mode-dependent component becomes responsible for both tasks with a consequent weakening of the principle of separation of concerns. This design pattern is useful in precisely this situation because it offers a way of separating the implementation of the mode-dependent behaviour from the implementation of the logic required to decide mode switches.
Dictionary Entries
The following abstractions or domain-wide concepts are defined to support the implementation of this design pattern:
Structure
The pattern class diagram in the figure illustrates the case of a mode-dependent component with two strategies. The mode dependent component uses a mode manager to supply to it the implementations of the strategies that are appropriate for a given operational situation. The two strategies are seen as instances of classes Strategy_1
and Strategy_2
. These could be concrete classes, or base abstract classes, or abstract interfaces. The mode manager is characterized by the ability to provide instances of these two classes to the mode-dependent component. It must therefore implement an abstract interface like ModeManager
in the figure that defines two getter methods for the two strategy implementations and two loader methods to associate the strategy implementations to the various modes managed by the mode manager. Concrete implementations of the ModeManager
interface provide the logic to switch between modes. This logic is implemented in a method like updateMode
that sets the current mode and therefore indirectly determines which implementers of the strategies are returned by calls to the getter methods.
Strategy_1
and Strategy_2
.
Participants
ModeDependentComponent
:The component whose behaviour needs to be made mode-dependent. ModeManager
:The abstract interface characterizing the component that is responsible for determining the operational mode and for providing the implementations of the strategies that are appropriate to the current operational conditions (namely, the implementations that are associated to the current operational mode). ConcreteModeManager
:A component implementing the ModeManager
interface and providing a particular implementation of mode-switching logic and a particular set of associations between operational modes and strategy implementations.Strategy_n
:An abstract interface, a base abstract class, or a concrete component representing an implementation of the n-th strategy managed by the mode-dependent component.
Collaborations
The typical operational scenario for this design pattern is:
-
During the configuration phase, the concrete implementations of the all the strategies managed by the mode-dependent component are loaded in the mode manager using its
loadStrategy
methods. - During the configuration phase, the mode manager is associated to the mode-dependent component (typically by loading it as a plug-in component).
-
During the normal operation phase, the mode manager is periodically activated to force it to update its operational model (its
update
method is called). - During the normal operation phase, whenever the mode-dependent component needs to implement one of its strategies, it interrogates its associated mode manager to obtain the correct implementation to use in current operational conditions (it calls its strategy getter methods).
Consequences
- It is easy to change the implementation of the strategies or the implementation of the mode switching logic independently from each other because they are encapsulated in distinct components.
- There may be a proliferation of classes as mode switching logic and strategies - or event implementations of individual strategies - come to need their own dedicated classes.
Applicability
Consider an application that is component-based and that has a need to tune its behaviour to changes in its operational environment. If it is not practical to define a single operational mode for the entire application and if operational mode is better seen as an attribute of individual components, then this design pattern helps defines an architecture that separates the implementation of the mode-dependent behaviours (the strategies) from the implementation of the mode management logic.
Implementation Issues
It would be useful to be able to define a generic ModeManager
abstract interface. This could probably be done using meta-language facilities (such as, for instance, Java reflection) or template meta-programming. In most cases, these techniques will not be acceptable for on-board applications and hence differences in the number and type of strategies and in the mode update mechanisms will usually mean that a dedicated mode manager interface must be defined for each mode-dependent component.
The mode manager maintains the operational mode of the mode-dependent component. Which mechanism should it use to update this operational mode in response to changes in the component's operational environment? The class diagram above shows the mode manager exposing an update
method that should be periodically called to give the mode manager a chance to check whether its operational mode needs to be updated. There are at least two alternative mechansisms. The mode manager might check for updates whenever one of the getter methods is called. This is a form of lazy update that is performed only when and if the mode-dependent component requires a new strategy implementation. Or, alternatively, the mode manager might use the classical observer pattern to ask to be notified whenever certain environmental parameters change and might use these notifications as opportunities to update its internal operational mode.
With the approach proposed here, the operational mode becomes a property of (some) application components. In order to ensure consistency of behaviour at the system level, it is necessary to ensure that changes in the operational mode of individual components are coordinated. Coordination will normally imply that a mode manager expose its operational mode as a monitorable property to give other components (possibly other mode managers) the chance to observe changes in its value and therefore to coordinate their behaviour with it.
OBS Framework Mapping
The implementation of this design pattern in the OBS Framework is supported by the following classes:
- ModeManagerabstract interface -->
TelemetryModeManager
,PunctualActionModeManager
Sample Code
Consider the example of the mode-dependent attitude controller component considered in the motivation section above. A skeleton code for this component could be as follows:
class AttitudeController { AttitudeSensor* sensor; AttitudeControlAlgorithm* controlAlgorithm; AttitudeControllerModeManager* modeManager; . . . void computeControlAction() { // Retrieve strategy implementers sensor = modeManager->getAttitudeSensor(); controlAlgorithm = modeManager->getControlAlgorithm (); // Use first strategy to acquire sensor data sensor->acquireData(); // Use second strategy to process the sensor data controlAlgorithm->processSensorData(); } }
The mode manager of this example will maintain two versions of the attitude control algorithms and two versions of the attitude sensor and will supply the appropriate one to the attitude controller algorithm based on operational conditions. The controller component can thus concentrate on computing the processing of the sensor data without having to keep track of changes in operational conditions.
Remarks
None
Author
A. Pasetti (P&P Software)
Last Modified
2002-12-12