Shared Data Design Pattern

Intent

Decouple the production of data from their consumption.

Based On

This pattern is essentially identical to the shared data design pattern of the AOCS Framework (see also: A. Pasetti, Embedded Control Systems and Software Frameworks, Springer-Verlag, 2002).

Motivation

Consider the case of an application built as a collection of components. These components interact by exchanging data. In a data exchange, the component that generates the data is called the data producer and the component that receives the data is called the data consumer. It is in general desirable desirable to decouple the producer from the consumer of the data. This has several advantages:

This design pattern proposes a solution to the problem of decoupling the production from the consumption of data in a component-based application.

In an embedded control application, two major categories of data can be recognized. Event data are produced asynchronously by components that wish to signal a change in their internal state or the occurrence of some event (e.g. the notification of an error condition). Cyclical data are instead data that are produced or consumed on a periodic basis by the application components (e.g. sensor read-out values). The chief characteristic of cyclical data is that, for a given category of data, only the latest value is of interest. In the case of event data, there is instead normally an interest in preserving all data values generated over a certain time interval. The solution proposed by this design pattern

Dictionary Entries

The following abstractions or domain-wide concepts are defined to support the implementation of this design pattern:

Structure

The solution proposed by this design pattern is based on a shared memory mechanism. Data pools are introduced to act as shared memory areas through which data are exchanged among application components. The data pools physically contain the data items. The producers of data deposit the data into the data pool and the consumers of data retrieve the data they need from the data pool.

As indicated by the class diagram of the pattern, there is normally only one producer for a certain type of datum but there may be multiple consumers (all of which access the same value of the data). Data consumers only retrieve copies of the data. The data always remain present in the data pool. This is essential to allow one-to-many exchanges between consumers and producers and to decouple the consumers from each other.

Normally, only one instance of a data of a certain type is stored in the pool. This means that if a data setter method is called twice, then the datum written to the pool at the second call overwrites the datum written at the first call. This mechanism is rigid but safe. It is suitable for cyclical data whose number and type is fixed and can be determined at design time. If these conditions do not hold (i.e. if the data are event-like), then a repository mechanism as proposed by the event design pattern may be considered as a solution to the problem of data exchanges among components.

An application can use several data pools with each individual data pool grouping together a set of logically related data.

Although the structure of a data pool component is simple, it is in general impossible to define a non-trivial base class from which more specific data pools can be derived or to define an abstract interface that should be implemented by all data pools. For this reason, it is not possible to map the abstract concept of data pool to any architectural construct. Data pools normally exist as concrete components only.

Participants

Collaborations

The typical operational scenario for this design pattern is:

Consequences

Applicability

This design pattern is useful when one or more of the following conditions hold:

Implementation Issues

Given the fixed structure of data pools, automatic generation of their code might often be a practical option. A very simple solution might be as follows. The structure of the data pool (the names and types of the data it must store, etc) is described in an XML file. An XSLT program is used to generate from it the source code of the data pool.

In its simplest form, a data pool simply offers a getter and a setter method for each data it holds. In this case, data consumers and producers must call the getter and, respectively, the setter methods whenever they want to access the data in the pool. In an alternative implementation instead the data pool offers a mechanism to allow an external component to establish a fixed link to the data in the pool. This could for instance be done using the data item mechanism proposed by the connection design pattern. In this case, the consumer and producer components are linked to the data pool during the application configuration phase but no longer need to directly access it subsequently.

Normally, for each setter method in a data pool, there is a matching getter method. In some cases, however, it is possible to have additional getter methods that return values that are obtained by combining the raw data that are set with the setter methods.

Data pools could be used to enforce some kind of access restrictions whereby certain data are only accessible for certain components. This could be done by implementing the data getter methods to check the identity of the consumer component and to deny access to unauthorized components. Similarly, the data setter methods could be implemented to allow only some components to change the value of a datum.

In most implementations, only the latest value of each datum in the data pool is preserved in the data pool. Where necessary, however, it would be easy to modify the proposed concept to hold sequences of values. In this case, the data pool concept becomes similar to the event repository concept of the event design pattern.

OBS Framework Mapping

The implementation of this design pattern in the OBS Framework is supported by the following classes:

Sample Code

As a very simple example of a concrete data pool, consider the following code:

	class SampleDataPool {

	  int data_a;
          float data_b;

          void setData_a(int val) {
             data_a = val;
	  }

          void setData_b(float val) {
             data_b = val;
          }

          int getData_a() {
             return data_a;
          }

          float getData_b() {
             return data_b;
          }

	}
The data pool in this example holds two items of data. More complex implementations might include mutual exclusion mechanisms for concurrent access or mechanisms for linking to the data in the pool (as opposed to reading/writing their values). However, in all cases, one will find that the data pool has a repetitive structure: the same basic structure is reproduced for each data that the pool holds. As already noted, this repetitive structure would often make it possible to generate the code for a data pool automatically from a description of the data they must hold.

Remarks

None

Author

A. Pasetti (P&P Software)

Last Modified

2003-05-14

Contact Us | The OBS Framework Project