Up to this point we have created a large number of
diagrams, tables, specification reports, and generated code. The
question is how do we integrate all the generated code and other
information from the various models. After you have completed
the model diagrams, tables, specification reports, and generated
code, you may integrate the various generated code listings into
the project code. The drawing below shows the progression. First
we generate class declaration and function definition files from
the class diagram. This is the basic code which we will add to
and modify. We place this generated code into the project and
compile, link, and execute with a simple main function. Next we
generate state class declarations and function definitions from
the state diagram. We update the project code by pasting data
and members into the project code. Next we generate the message
sequence table from the object interaction diagram. We paste the
messages into the project code. Next we generate the detailed
operation table showing transformations, preconditions, and postconditions.
We paste the function statements into the project code. We update
the main function to be a complete test case. At this point we
should have a complete executable prototype that meets the system
requirements statement and use case descriptions. However, many,
many iterations are required until the prototype is satisfactory.
As shown on the drawing below, it may be necessary
to integrate GUI resource code, persistent storage code, and distribution
code.
The following are the steps to create an executable
prototype using a CASE tool and a C++ compiler.
Step 1 - In the object model, create the class diagram.
Show initializer, interface, control, and entity classes. Generate
C++ from the class diagram using a C++ code generation script,
e.g. CPPHDMIN.SCT for the header files and CPPFUMIN.SCT for the
function definition files. Place the files into the project directory.
Step 2 - Create a simple main function that creates
an object. Later update the main function to send messages representing
the input events in each use case. Compile, link, and execute
the project.
Step 3 - In the dynamic model, create a state diagram
for each control class. Generate C++ from each state diagram for
each control class using a C++ code generation script, e.g. STAHEAD1.SCT
for the header files and STAFUNC1.SCT for the function definition
files. Integrate the generated the control class code into the
object model generated code. Compile, link, and execute the project.
Step 4 - In the dynamic model, create an object interaction
diagram for each use case. Create the message sequence table with
a script, e.g. TABOBMSG.SCT. Copy messages from the message sequence
table into the generated object model code in the project directory.
Insert messages in the sender functions in the interface, control,
and entity classes. Compile, link, and execute the project.
Step 5 - In the functional model, create the operation
specification showing transformations and correctness assertions.
Create the operation table showing function information. For each
function place the transformation and correctness assertion statements.
Compile, link, and execute the project.
Step 6 - Double check to ensure that the executable
prototype fulfills all requirements in the requirements statement
and all use cases.
Step 7 - Reverse engineer the code to create a class diagram.
The following is the "reverse engineered" diagram based upon the compiled C++ source code. Notice that this class diagram shows the constructors, destructors, and all data members. It shows the data members that implement the aggregation relationship, e.g. theChannel.
The following is the compiled C++ code for the TV Control System. The actual project consists of a header file for each class, a definition file (.cpp) for each class, and a main function file. This project code was initially generated from a class diagram. Then the project code was updated with generated code from a state diagram. Then the project code was updated based upon the message sequence tables from an object interaction diagram. Then the project code was updated with transformations and preconditions from the detailed operation table generated from the operation specifications. Key points about this project code are:
- No initializer class is required; a main function is used.
- State transition logic is in the TVController class.
- The TVButtonsInterface class handles all input events.
- Transformations are in the Volume and Channel classes. Preconditions are implemented. Postconditions and exceptions are not implemented. Only cout statements are used to indicate errors.
- Main function is a simple test case to implement
the use cases.
///////////////////// Class: TVButtonsInterface .h file////////////////////////////
#ifndef __TVBTTINT_H //Required for current class TVButtonsInterface
#define __TVBTTINT_H
//Required for 1:1 aggregation (part) classes
#ifndef __TVCNTRLL_H //TVController
#include "TVCntrll.h"
#endif
class TVButtonsInterface
{
TVController theTVController; //1:1 aggregation part data member
public:
TVButtonsInterface (); //Default constructor
void turnOn () ;
void increaseVolume () ;
void decreaseVolume () ;
void increaseChannel () ;
void decreaseChannel () ;
void turnOff () ;
~ TVButtonsInterface ( ) { } //Destructor
};
#endif
///////////////////// Class: TVController .h file////////////////////////////
#ifndef __TVCNTRLL_H //Required for current class TVController
#define __TVCNTRLL_H
//Required for 1:1 aggregation (part) classes
#ifndef __STRDVCIN_H //StorageDeviceInterface
#include "StrDvcIn.h"
#endif
//Required for 1:1 aggregation (part) classes
#ifndef __CHNDVCIN_H //ChannelDeviceInterface
#include "ChnDvcIn.h"
#endif
//Required for 1:1 aggregation (part) classes
#ifndef __VOLUME_H //Volume
#include "Volume.h"
#endif
//Required for 1:1 aggregation (part) classes
#ifndef __CHANNEL_H //Channel
#include "Channel.h"
#endif
//Required for 1:1 aggregation (part) classes
#ifndef __SPKDVCIN_H //SpeakerDeviceInterface
#include "SpkDvcIn.h"
#endif
enum States { OffState, Terminal, OnState };
class TVController
{
States currentState;
int volumeSetting; //Attribute data member
int channelSetting; //Attribute data member
StorageDeviceInterface theStorageDeviceInterface; //1:1 aggregation part data member
ChannelDeviceInterface theChannelDeviceInterface; //1:1 aggregation part data member
Volume theVolume; //1:1 aggregation part data member
Channel theChannel; //1:1 aggregation part data member
SpeakerDeviceInterface theSpeakerDeviceInterface; //1:1 aggregation part data member
public:
TVController () ; //Default constructor
void turnOn() ;
void increaseVolume() ;
void decreaseChannel() ;
void increaseChannel() ;
void decreaseVolume() ;
void turnOff() ;
~ TVController ( ) { } //Destructor
};
#endif
///////////////////// Class: TVItem .h file////////////////////////////
#ifndef __TVITEM_H //Required for current class TVItem
#define __TVITEM_H
class TVItem
{
protected:
int aSetting; //Attribute data member
int maxSetting;//Attribute data member
int minSetting; //Attribute data member
public:
TVItem (); //Default constructor
void setSetting (int setting) ;
int getSetting () ;
virtual void increase () ;
virtual void decrease () ;
virtual ~ TVItem ( ) { } //Destructor
};
#endif
///////////////////// Class: Volume .h file////////////////////////////
#ifndef __VOLUME_H //Required for current class Volume
#define __VOLUME_H
//Required for base classes
#ifndef __TVITEM_H //TVItem
#include "TVItem.h"
#endif
class Volume : public TVItem
{
public:
Volume (); //Default constructor
void increase () ;
void decrease () ;
~ Volume ( ) { } //Destructor
};
#endif
///////////////////// Class: Channel .h file////////////////////////////
#ifndef __CHANNEL_H //Required for current class Channel
#define __CHANNEL_H
//Required for base classes
#ifndef __TVITEM_H //TVItem
#include "TVItem.h"
#endif
class Channel : public TVItem
{
public:
Channel (); //Default constructor
void increase () ;
void decrease () ;
~ Channel ( ) { } //Destructor
};
#endif
///////////////////// Class: ChannelDeviceInterface .h file////////////////////////////
#ifndef __CHNDVCIN_H //Required for current class ChannelDeviceInterface
#define __CHNDVCIN_H
class ChannelDeviceInterface
{ int channelSetting; //Attribute data member
public:
ChannelDeviceInterface (); //Default constructor
void setChannel (int aChannelSetting) ;
~ ChannelDeviceInterface ( ) { } //Destructor
};
#endif
///////////////////// Class: SpeakerDeviceInterface .h file////////////////////////////
#ifndef __SPKDVCIN_H //Required for current class SpeakerDeviceInterface
#define __SPKDVCIN_H
class SpeakerDeviceInterface
{
int volumeSetting; //Attribute data member
public:
SpeakerDeviceInterface (); //Default constructor
void setVolume (int aVolumeSetting) ;
~ SpeakerDeviceInterface ( ) { } //Destructor
};
#endif
///////////////////// Class: StorageDeviceInterface .h file////////////////////////////
#ifndef __STRDVCIN_H //Required for current class StorageDeviceInterface
#define __STRDVCIN_H
class StorageDeviceInterface
{
int volumeSetting; //Attribute data member
int channelSetting; //Attribute data member
public:
StorageDeviceInterface (); //Default constructor
int retrieveVolume () ;
void storeVolume (int aVolumeSetting) ;
int retrieveChannel () ;
void storeChannel (int aChannelSetting) ;
~ StorageDeviceInterface ( ) { } //Destructor
};
#endif
////////////////// Class: TVButtonsInterface .cpp file//////////////////////////////////
#include "TVBttInt.h"
void TVButtonsInterface::turnOn()
{ theTVController.turnOn();
}
void TVButtonsInterface::increaseVolume()
{ theTVController.increaseVolume();
}
void TVButtonsInterface::decreaseVolume()
{ theTVController.decreaseVolume();
}
void TVButtonsInterface::increaseChannel()
{ theTVController.increaseChannel();
}
void TVButtonsInterface::decreaseChannel()
{ theTVController.decreaseChannel();
}
void TVButtonsInterface::turnOff()
{ theTVController.turnOff();
}
TVButtonsInterface::TVButtonsInterface ()
{
}
////////////////////////// Class: TVController .cpp file//////////////////////////////////
#include "TVCntrll.h"
#include <iostream.h>
void TVController::turnOn()
{if ( ( currentState == OffState ) && (1) )
{ volumeSetting = theStorageDeviceInterface.retrieveVolume();
theVolume.setSetting (volumeSetting);
channelSetting = theStorageDeviceInterface.retrieveChannel();
theChannel.setSetting (channelSetting);
theSpeakerDeviceInterface.setVolume(volumeSetting);
theChannelDeviceInterface.setChannel(channelSetting);
currentState = OnState;
cout << "TV turned on - state is OnState" << "The volume is " << volumeSetting
<< "The channel is " << channelSetting << endl;
return;
}
}
void TVController::increaseVolume()
{if ( ( currentState == OnState ) && (1) )
{ theVolume.increase();
volumeSetting = theVolume.getSetting ();
cout << "Increased volume - state is OnState" << "The volume is " << volumeSetting << endl;
theSpeakerDeviceInterface.setVolume(volumeSetting);
currentState = OnState;
return;
}
}
void TVController::decreaseChannel()
{if ( ( currentState == OnState ) && (1) )
{ theChannel.decrease();
channelSetting = theChannel.getSetting();
cout << "Decreased channel - state is OnState" << "The channel is " << channelSetting << endl;
theChannelDeviceInterface.setChannel(channelSetting);
currentState = OnState;
return;
}
}
void TVController::increaseChannel()
{if ( ( currentState == OnState ) && (1) )
{ theChannel.increase();
channelSetting = theChannel.getSetting();
cout << "Increased channel - state is OnState" << "The channel is " << channelSetting << endl;
theChannelDeviceInterface.setChannel (channelSetting);
currentState = OnState;
return;
}
}
void TVController::decreaseVolume()
{if ( ( currentState == OnState ) && (1) )
{ theVolume.decrease();
volumeSetting = theVolume.getSetting();
cout << "Decreased volume - state is OnState" << "The volume is " << volumeSetting << endl;
theSpeakerDeviceInterface.setVolume(volumeSetting);
currentState = OnState;
return;
}
}
void TVController::turnOff()
{if ( ( currentState == OnState ) && (1) )
{ theStorageDeviceInterface.storeVolume(volumeSetting);
theStorageDeviceInterface.storeChannel(channelSetting);
currentState = Terminal;
cout << "TV turned off - state is Terminal" << "The volume is " << volumeSetting
<< "The channel is " << channelSetting << endl;
return;
}
}
TVController::TVController () : currentState
( OffState ), volumeSetting (0), channelSetting (0) { }
////////////////// Class: TVController .cpp file///////////
#include "TVCntrll.h"
#include <iostream.h>
void TVController::turnOn()
{if ( ( currentState == OffState ) && (1) )
{ volumeSetting = theStorageDeviceInterface.retrieveVolume();
theVolume.setSetting (volumeSetting);
channelSetting = theStorageDeviceInterface.retrieveChannel();
theChannel.setSetting (channelSetting);
theSpeakerDeviceInterface.setVolume(volumeSetting);
theChannelDeviceInterface.setChannel(channelSetting);
currentState = OnState;
cout << "TV turned on - state is OnState";
return;
}
}
void TVController::increaseVolume()
{if ( ( currentState == OnState ) && (1) )
{ theVolume.increase();
volumeSetting = theVolume.getSetting (); cout << "The volume is " << volumeSetting;
theSpeakerDeviceInterface.setVolume(volumeSetting);
currentState = OnState;
cout << "Increased volume - state is OnState";
return;
}
}
void TVController::decreaseChannel()
{if ( ( currentState == OnState ) && (1) )
{ theChannel.decrease();
channelSetting = theChannel.getSetting(); cout << "The channel is " << channelSetting;
theChannelDeviceInterface.setChannel(channelSetting);
currentState = OnState;
cout << "Decreased channel - state is OnState";
return;
}
}
void TVController::increaseChannel()
{if ( ( currentState == OnState ) && (1) )
{ theChannel.increase();
channelSetting = theChannel.getSetting(); cout << "The channel is " << channelSetting;
theChannelDeviceInterface.setChannel (channelSetting);
currentState = OnState;
cout << "Increased channel - state is OnState";
return;
}
}
void TVController::decreaseVolume()
{if ( ( currentState == OnState ) && (1) )
{ theVolume.decrease();
volumeSetting = theVolume.getSetting(); cout << "The volume is " << volumeSetting;
theSpeakerDeviceInterface.setVolume(volumeSetting);
currentState = OnState;
cout << "Decreased volume - state is OnState";
return;
}
}
void TVController::turnOff()
{if ( ( currentState == OnState ) && (1) )
{ theStorageDeviceInterface.storeVolume(volumeSetting);
theStorageDeviceInterface.storeChannel(channelSetting);
currentState = Terminal;
cout << "TV turned off - state is Terminal";
return;
}
}
TVController::TVController () : currentState ( OffState ), volumeSetting (0), channelSetting (0) { } //Constructor
////////////////////////// Class: TVItem .cpp file//////////////////////////////////
#include "TVItem.h"
void TVItem::setSetting (int setting)
{ aSetting = setting;
}
int TVItem::getSetting()
{ return aSetting;
}
void TVItem::increase()
{
}
void TVItem::decrease()
{
}
TVItem::TVItem ()
: aSetting(0), minSetting (0), maxSetting (99)
{
}
////////////////////////// Class: Volume .cpp file//////////////////////////////////
#include "Volume.h"
#include <iostream.h>
void Volume::increase()
{ if (aSetting < maxSetting) aSetting = aSetting + 1;
else cout << "Cannot increment volume";
}
void Volume::decrease()
{ if (aSetting > minSetting) aSetting = aSetting - 1;
else cout << "Cannot decrease volume";
}
Volume::Volume ()
{
}
////////////////////////// Class: Channel .cpp file//////////////////////////////////
#include "Channel.h"
#include <iostream.h>
void Channel::increase()
{ if (aSetting < maxSetting) aSetting = aSetting + 1;
else cout << "Cannot increment channel";
}
void Channel::decrease()
{ if (aSetting > minSetting) aSetting = aSetting - 1;
else cout << "Cannot decrease channel";
}
Channel::Channel ()
{
}
//////////// Class: ChannelDeviceInterface .cpp file////////////////////////////////
#include "ChnDvcIn.h"
void ChannelDeviceInterface::setChannel(int aChannelSetting)
{ channelSetting = aChannelSetting;
}
ChannelDeviceInterface::ChannelDeviceInterface ()
: channelSetting(0)
{
}
/////////////// Class: SpeakerDeviceInterface .cpp file//////////////////////////////////
#include "SpkDvcIn.h"
void SpeakerDeviceInterface::setVolume(int aVolumeSetting)
{ volumeSetting = aVolumeSetting;
}
SpeakerDeviceInterface::SpeakerDeviceInterface ()
: volumeSetting(0)
{
}
////////////// Class: StorageDeviceInterface .cpp file////////////////////////////////
#include "StrDvcIn.h"
int StorageDeviceInterface::retrieveVolume()
{ return volumeSetting;
}
void StorageDeviceInterface::storeVolume(int aVolumeSetting)
{
}
int StorageDeviceInterface::retrieveChannel()
{ return channelSetting;
}
void StorageDeviceInterface::storeChannel(int aChannelSetting)
{
}
StorageDeviceInterface::StorageDeviceInterface ()
: volumeSetting(0), channelSetting(0)
{
}
/////////////////main.cpp//////////////////////////////////////////////////////////////
#include "tvbttint.h"
int main ()
{ TVButtonsInterface theTVButtonsInterface;
theTVButtonsInterface.turnOn ();
theTVButtonsInterface.increaseVolume ();
theTVButtonsInterface.increaseChannel ();
theTVButtonsInterface.decreaseVolume ();
theTVButtonsInterface.decreaseChannel ();
theTVButtonsInterface.turnOff ();
return 0;}
Sample Output
TV turned on - state is OnState The volume is 0 The channel is 0
Increased volume - state is OnState The volume is 1
Increased channel - state is OnState The channel is 1
Decreased volume - state is OnState The volume is 0
Decreased channel - state is OnState The channel is 1
TV turned off - state is Terminal The volume is 0 The channel is 0
The purpose of this chapter was to present the steps and guidelines to create an executable C++ prototype by generating C++ code from the class diagram, state diagram, and object interaction diagram.