9.8 Container Pattern


Analysis models the what of a system what it is, what fundamental concepts are involved, and what the important relations and associations among them are. Design specifies the how of all the unspecified portions of the system. One of the important hows of design is how message transport for each and every message will be implemented is it a function call, an OS mail message, a bus message, an RPC, or something even more exotic? Another important how is the resolution of associations with multivalued roles.

When an object has a one-to-many association, the question arises as to the exact mechanism the "one" class will use to access the "many" objects. One solution is to build features into the "one" class to manage the set of contained objects. These facilities typically manifest themselves as operations such as add(), remove(), first(), next(), last(), and find(). Often the semantics of the associate dictate elaborate operations, such as maintaining the set of objects in a specific order or balancing the tree. Building these features into each and every class that must maintain a one-to-many association is repugnant for several reasons outlined in Section 9.1. The common solution to these problems is to insert a container object (also called a collection object) between the "one" and the "many."

Adding a container object to manage the aggregated objects doesn't entirely solve the problem because often the container must be accessed from several clients. If the container keeps track of the client position, it will become confused in a multiclient environment. To get around this, iterators are used in conjunction with the containers. An iterator keeps track of where the client is in the container. Different clients use different iterators, so the separate concerns of managing the collection and tracking position within the container are abstracted away from each other. A single client may use several different iterators. The Standard Template Library (STL), a part of the ANSI C++ standard, provides many different containers with a variety of iterators, such as first, last, and so on.

9.8.1 Abstract

The container pattern reifies the association itself as a class dedicated to the management of multiple instances. This solution can easily take advantage of container libraries that offer various containers that are optimal under different conditions, and can be done by some UML tools automatically.

9.8.2 Problem

The obvious form of association realization pointers and references only work in their naïve form for multiplicities of 1 1 or (0,1) (0,1). Their implementation for multivalued roles (e.g., *) isn't obvious. Simply adding containment management to one of the existing classes complicates that class with a set of semantics unrelated to its normal purpose. Further, it is important in many circumstances that the same collection of objects be used by multiple clients without the access by one client affecting any of the others.

9.8.3 Pattern Structure

The container pattern addresses the realization of multivalued association multiplicities by inserting a class between the classes in question, one charged with the management of collection management. Different kinds of collection classes can be used to optimize different qualities of service, such as memory space, read access time, write access time, searching, and so on. Additionally, the use of iterators allows the collection to be used by multiple clients without the access of one client affecting the access of another.

Like the guarded call pattern, the container pattern is very simple, although the container itself may be quite complex internally. This pattern will be elaborated more in the next pattern (the Rendezvous Pattern).

Figure 9-14. Container Pattern

graphics/09fig14.jpg

9.8.4 Collaboration Roles

The following objects participate in the container pattern:

  • Container: The Container object manages the collection and provides accessor operations.

  • Iterator: The Iterator acts like a smart pointer and mediates access to the parts for the client. An iterator query access, such as first() or next(), typically returns a pointer to a Part object. Insertion and deletion of parts may also be mediated through the iterator.

  • Client: The Client is the object needing access to the Part objects managed by the Container.

  • Part: The Part objects are the objects managed by the Container object. In a system managing bank accounts, for example, the Part objects might be individual accounts or transactions within those accounts.

9.8.5 Consequences

The container pattern provides good isolation of the techniques and complexities of part management by abstracting the container into a separate class to manage the (possibly) many contained parts. The use of iterators allows the same Container to be used by several clients as well, at the cost of some complexity due to the use of such iterators.

9.8.6 Implementation Strategies

The most common implementation of this pattern is to elaborate one-to-many relationships between a client and parts to a one-to-one relationship to the client and the part container, and a one-to-many relation from the part container to the parts. The container and iterators are most commonly taken from a container library, such as STL. Rhapsody does the elaboration and implementation of the containers directly, either with their built-in container library or with the STL (C++ only).

9.8.7 Sample Model

The example of this pattern, shown in Figure 9-15, is an aircraft flight planning system. A flight plan consists of a set of waypoints. Each waypoint contains a name, an altitude, and a position in terms of latitude and longitude. The flight plan must manage arbitrary number of waypoints. This includes operations such as these:

  • nWaypoints(), which returns the number of waypoints in the flight plan

  • mininumAltitude(), which searches the set of waypoints and returns the lowest altitude of any of the waypoints

  • pathDistance(), which computes the distance along a path, assuming a minimum flight distance between waypoints

Figure 9-15a. Container Pattern Example

graphics/09fig15.gif

Figure 9-15b. Container Pattern Example

graphics/09fig15_01.jpg

Each of these operations, as well as the facility to add and remove waypoints in the flight plan, requires the FlightPlan class to manipulate the set of waypoints. In this case, this is via the application of the container pattern, implemented, in this case, with the vector template. Code Listing 9-2 shows the FlightPlan.h file and 9-3 shows the corresponding FlightPlan.cpp file. The operation implementation is shown in this latter file. An iterator is used to scan the list of waypoints. The iterator starts at the beginning of the list using the special begin() iterator and terminates at the end of the list with the special end() iterator. The use of this is illustrated by the body of the nWaypoints() operation, which simply counts the number of waypoints.

Code Listing 9-2. FlightPlan.h
 int n = 0;     vector<Waypoint*>::const_iterator trailBlazer;     for (trailBlazer = itsWP.begin(); trailBlazer !=          itsWP.end(); ++trailBlazer) {          ++n;       };      return n; /*****************************************************    Rhapsody : 5.0    Login    : Bruce    Component   : DefaultComponent    Configuration  : DefaultConfig    Model Element  : FlightPlan //!   Generated Date  : Sun, 3, Aug 2003    File Path   : DefaultComponent\DefaultConfig\                  FlightPlan.h *****************************************************/ #ifndef FlightPlan_H #define FlightPlan_H #include <oxf/oxf.h> #include <string> #include <algorithm> #include "math.h" #include "Default.h" #include <vector> #include <iterator> #include "Waypoint.h" //## package Default // // FlightPlan.h // #ifdef _MSC_VER // disable Microsoft compiler warning (debug // information truncated) #pragma warning(disable: 4786) #endif //## class FlightPlan class FlightPlan  { ////    Constructors and destructors    //// public :     //## auto_generated     FlightPlan();     //## auto_generated     ~FlightPlan(); ////    Operations    //// public :     //## operation displayList()     void displayList();     // Returns the minimum altitude in the flight plan     //## operation minimumAltitude()     double minimumAltitude();     //## operation nWaypoints()     int nWaypoints();     //## operation pathDistance()     double pathDistance(); // Distance calculation in miles is sqrt(x^2 + y^2) // where x= 69.1*(lat2 lat1) and y = 69.1*(lon2 // lon1)*cos(lat1/57.3). // More accurate conversion can be done by using the    greater distance // formula. //## operation ptDistance(double,double,double,double) double ptDistance(double lat1, double lon1, double   lat2, double lon2); ////    Additional operations    //// public :     //## auto_generated     std::vector<Waypoint*>::const_iterator getItsWP()       const;     //## auto_generated     std::vector<Waypoint*>::const_iterator       getItsWPEnd() const;     //## auto_generated     void addItsWP(Waypoint* p_Waypoint);     //## auto_generated     void removeItsWP(Waypoint* p_Waypoint);     //## auto_generated     void clearItsWP(); ////    Framework operations    //// public :     //## auto_generated     void _addItsWP(Waypoint* p_Waypoint);     //## auto_generated     void _removeItsWP(Waypoint* p_Waypoint);     //## auto_generated     void _clearItsWP(); protected :     //## auto_generated     void cleanUpRelations(); ////    Relations and components    //// protected :     std::vector<Waypoint*> itsWP;      //## link itsWP }; #endif /*****************************************************    File Path   : DefaultComponent\DefaultConfig\                  FlightPlan.h *****************************************************/ 
Code Listing 9-3. FlightPlan.cpp
 /*****************************************************    Rhapsody : 5.0    Login    : Bruce    Component   : DefaultComponent    Configuration  : DefaultConfig    Model Element  : FlightPlan //!   Generated Date : Sun, 3, Aug 2003    File Path   : DefaultComponent\DefaultConfig\                  FlightPlan.cpp *****************************************************/ #include "FlightPlan.h" //## package Default // // FlightPlan.cpp // //## class FlightPlan FlightPlan::FlightPlan() { } FlightPlan::~FlightPlan() {     cleanUpRelations(); } void FlightPlan::displayList() {     //#[ operation displayList()     vector<Waypoint*>::const_iterator trailBlazer;     for (trailBlazer = itsWP.begin(); trailBlazer !=       itsWP.end(); ++trailBlazer) {        (*trailBlazer)->display();     };     cout << "DONE" << endl;     //#] } double FlightPlan::minimumAltitude() {     //#[ operation minimumAltitude()     double minAlt= 1E06;     double altitude;     vector<Waypoint*>::const_iterator trailBlazer;     for (trailBlazer = itsWP.begin(); trailBlazer !=       itsWP.end(); ++trailBlazer) {          altitude = (*trailBlazer)->getAltitude();       if (minAlt > altitude) minAlt = altitude;       };      return minAlt;     //#] } int FlightPlan::nWaypoints() {     //#[ operation nWaypoints()     int n = 0;     vector<Waypoint*>::const_iterator trailBlazer;     for (trailBlazer = itsWP.begin(); trailBlazer != itsWP.end(); ++trailBlazer) {          ++n;       };      return n;     //#] } double FlightPlan::pathDistance() {     //#[ operation pathDistance()     double distance = 0;     double lat1,lon1,lat2,lon2;     vector<Waypoint*>::const_iterator trailBlazer;     if (nWaypoints() > 1) {       trailBlazer = itsWP.begin();       lat1 = (*trailBlazer)->getLatitude();       lon1 = (*trailBlazer)->getLongitude();       for (trailBlazer = itsWP.begin()+1; trailBlazer            != itsWP.end(); ++trailBlazer) {              lat2 = (*trailBlazer)->getLatitude();              lon2 = (*trailBlazer)->getLongitude();             distance += ptDistance(lat1, lon1, lat2,               lon2);             lat1=lat2;             lon1=lon2;             };     };     return distance;     //#] } double FlightPlan::ptDistance(double lat1, double   lon1, double lat2, double lon2) {     //#[ operation ptDistance(double,double,double,double)     double x,y, distance;     x = 69.1*(lat2 lat1);     y = 69.1*(lon2 lon1)*cos(lat1/57.3);     distance = sqrt(x*x + y*y);     return distance;     //#] } std::vector<Waypoint*>::const_iterator   FlightPlan::getItsWP() const {     std::vector<Waypoint*>::const_iterator iter;     iter = itsWP.begin();     return iter; } std::vector<Waypoint*>::const_iterator   FlightPlan::getItsWPEnd() const {     return itsWP.end(); } void FlightPlan::_addItsWP(Waypoint* p_Waypoint) {     itsWP.push_back(p_Waypoint); } void FlightPlan::addItsWP(Waypoint* p_Waypoint) {     if(p_Waypoint != NULL)         {             p_Waypoint->_setItsFlightPlan(this);         }     _addItsWP(p_Waypoint); } void FlightPlan::_removeItsWP(Waypoint* p_Waypoint) {     std::vector<Waypoint*>::iterator pos =       std::find(itsWP.begin(),       itsWP.end(),p_Waypoint);     if (pos != itsWP.end()) {       itsWP.erase(pos);     }; } void FlightPlan::removeItsWP(Waypoint* p_Waypoint) {     if(p_Waypoint != NULL)         {             p_Waypoint->__setItsFlightPlan(NULL);         }     _removeItsWP(p_Waypoint); } void FlightPlan::_clearItsWP() {     itsWP.clear(); } void FlightPlan::clearItsWP() {     std::vector<Waypoint*>::const_iterator iter;     iter = itsWP.begin();     while (iter != itsWP.end()){         (*iter)->_clearItsFlightPlan();         iter++;     }     _clearItsWP(); } void FlightPlan::cleanUpRelations() {     {         std::vector<Waypoint*>::const_iterator iter;         iter = itsWP.begin();         while (iter != itsWP.end()){             FlightPlan* p_FlightPlan = (*iter)->               getItsFlightPlan();             if(p_FlightPlan != NULL)                 {                     (*iter)->__setItsFlightPlan(NULL);                 }             iter++;         }         itsWP.clear();     } } /*****************************************************    File Path   : DefaultComponent\DefaultConfig\                  FlightPlan.cpp *****************************************************/ 


Real Time UML. Advances in The UML for Real-Time Systems
Real Time UML: Advances in the UML for Real-Time Systems (3rd Edition)
ISBN: 0321160762
EAN: 2147483647
Year: 2003
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net