Delphi Program Development With Class

by Richard Felsinger , RCF Associates, 960 Scottland Dr, Mt Pleasant, SC 29464

Telephone 803-881-3648 e-mail 71162.755@compuserve.com

Comprehensive O-O Model Building and C++/Java/Delphi Development and Training Available

The purpose of this tutorial is to present how-to use the With Class CASE tool to develop Delphi programs. With Class is a scripting CASE tool which permits the creation of object-oriented diagrams, text specifications, and code generation. In this tutorial we separate the user interface classes from application (problem domain) classes. To create Delphi applications, we will follow these steps:

1 - In Delphi, create a Delphi Project and create the user interface consisting of forms, menus, dialog boxes, etc.

2 - Identify the application/problem domain entities (classes) that hold application information and process application information with algorithms.

3 - Create a class diagram of application (problem domain) classes in With Class.

4 - Generate Delphi code from the class diagram using a script, e.g. DELBASIC.SCT.

5 - In Delphi, add the generated code .pas files into the Delphi project.

6 - Compile and execute the project.

7 - Attach the user interface form (Form1) with the application classes, e.g. create application objects and create messages to the application objects.

8 - After modifying the Delphi code, reverse engineer the code in With Class to create a reversed class diagram.

Using With Class to Create a Class Diagram and Generate Delphi Code

To create your first Delphi program in With Class, launch With Class and set the Utilities - Preferences to Delphi. Create the class diagram, counter.omt. Select the class icon or Draw - Class. Place the class on the diagram. Enter the class name Counter. Enter the attribute Value. Enter the operation names Increment and Decrement. To display the maximum information on the class diagram, select View - Show Class - then select Show Type, Show Visibility, Show Operation Parameters, and Show Attributes/Operation Properties. On the class diagram, the - indicates private visibility, the + indicates public visibility, and the # indicates protected visibility. To generate Delphi code select Utilities - Generate Code per File. Select Delphi. If necessary, select Browse to find the script file DELBASIC.SCT. To view the generated code counter.pas, select File - Edit File and open counter.pas. Then open Delphi, create a project, add counter.pas. Compile and execute the project.



Once you have created the class diagram, double click on the class to bring up the Class Form shown below.




In the Class Form, click on the Spec Button to update the class specification shown below.


On the Class Form, double click on the attribute to bring up the Attribute Specification. Enter the Attribute Type, e.g. Integer, Attribute Visibility, e.g. private, and the Attribute Initial Value, e.g. 0. As appropriate, check a box for Constant, Static (Class), Array, Read Property, or Write Property. The script DELALL.SCT generates read and write property code statements.



On the Class Form, double click on the Increment operation to bring up the Operation Specification shown below. Enter the Operation Return Type for the procedure and the Operation Visibility, e.g. public. For each parameter enter the parameter type/class name followed by the parameter name similar to C++ form, e.g. Integer anIntegerParameter. With Class will generate the Delphi parameters, e.g. anIntegerParameter : Integer.


Click on the Code button to bring up the Code Form shown below. Enter Delphi code for the Increment Operation, e.g. Value = Value + 1; Later, if you update this code in the Delphi Editor, you can import the updated code by selecting the Import Delphi button.


Once the class diagram and all specifications have been completed, you may generate Delphi code by selecting Utilities - Generate Code File per Class shown below. Select Delphi and the script DELBASIC.SCT.


The DELBASIC.SCT script is listed below. This is the most basic Delphi code generation script. This script reads the class diagram and creates the Counter.pas Delphi code file. Key points about this script:

- T is prefixed to each class name, e.g. Counter on the diagram becomes TCounter class in the generated code.

- All attributes (Delphi fields) and aggregation role names (Delphi fields) are private.

- All association role names (Delphi fields) and operations (Delphi methods) are public

- 1 to 1 Association is implemented by creating a Delphi field but no object is created. The field may be set to nil in the constructor. The caller must new and free the 1 to 1 Association object.

- 1 to 1 Aggregation is implemented by creating a Delphi field and creating an object. This means new should be used in constructors and free should be used in destructors for 1:1 aggregation part objects.

- 1 to Many Association and 1 to Many Aggregation relationships are implemented as arrays. You must update the array index with the correct multiplicity, e.g.[1..4];

- Create constructor and Destroy destructor are created.

- Uses statement is generated including unit names for Inheritance - Ancestor Classes, 1 to 1 Association, 1 to 1 Aggregation, 1 to Many Association, and 1 to Many Aggregation, e.g. uses SysUtils, Messages, Classes ;

Script to Generate Delphi Code - DELBASIC.SCT - Very Basic Code - Starting Point

CLASS_USER1

unit CLASS_NAME;

interface

CLASS_USER2

CLASS_USER3

uses SysUtils, Messages, Classes [,DELETE_LAST_SYMBOL BASE_CLASS ][,DELETE_LAST_SYMBOL ASSOCIATION_ONE_CLASS ][,DELETE_LAST_SYMBOL AGGREGATION_ONE_CLASS ][,DELETE_LAST_SYMBOL ASSOCIATION_MANY_CLASS ][,DELETE_LAST_SYMBOL AGGREGATION_MANY_CLASS ][,DELETE_LAST_SYMBOL INCLUDE_FILE ] ;

type

T$CLASS_NAME = class [(T$BASE_CLASS)]

private

[COLUMN_TAB(4) ATTRIBUTE_NAME : ATTRIBUTE_TYPE ; ]

[COLUMN_TAB(4) AGGREGATION_ONE_NAME : T$AGGREGATION_ONE_CLASS ; ]

[COLUMN_TAB(4) AGGREGATION_MANY_NAME : array LITERAL_SYMBOL[1..10 LITERAL_SYMBOL] of T$AGGREGATION_MANY_CLASS ; ]

public

[COLUMN_TAB(4) ASSOCIATION_ONE_NAME : T$ASSOCIATION_ONE_CLASS ; ]

[COLUMN_TAB(4) ASSOCIATION_MANY_NAME : array LITERAL_SYMBOL[1..10 LITERAL_SYMBOL] of T$ASSOCIATION_MANY_CLASS ; ]

constructor Create; virtual; {replace virtual with override in derived classes}

destructor Destroy ; override;

SELECT_WHEN OPERATION_IS_PROCEDURE [

procedure OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE ]

SELECT_WHEN OPERATION_IS_FUNCTION [

function OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE]

end;

implementation

{-------------------------------------------------------------------------------}

constructor T$CLASS_NAME$.Create;

begin

inherited Create ;

{ Place code here }

end;

{-------------------------------------------------------------------------------}

{Update as required.}

destructor T$CLASS_NAME$.Destroy ;

begin

{ Place code here }

inherited Destroy;

end;

SELECT_WHEN OPERATION_IS_PROCEDURE

[{------------------------------------------------------------------------------}

procedure T$CLASS_NAME.OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ;

begin

{ Place code here }

OPERATION_CODE

end;

]

SELECT_WHEN OPERATION_IS_FUNCTION

[{------------------------------------------------------------------------------}

function T$CLASS_NAME.OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ;

begin

{ Place code here and return an object }

OPERATION_CODE

end;

]

end.

Generated Delphi Code for the Counter Unit - counter.pas - Very Basic

unit Counter;

interface

uses SysUtils, Messages, Classes ;

type

TCounter = class

private

Value : Integer ;

public

constructor Create; virtual; {replace virtual with override in derived classes}

destructor Destroy ; override;

procedure Increment ;

procedure Decrement ;

end;

implementation

{-------------------------------------------------------------------------------}

constructor TCounter.Create;

begin

inherited Create ;

{ Place code here }

end;

{-------------------------------------------------------------------------------}

destructor TCounter.Destroy ; {Update as required.}

begin

{ Place code here }

inherited Destroy;

end;

{-------------------------------------------------------------------------------}

procedure TCounter.Increment ;

begin

{ Place code here }

end;

{-------------------------------------------------------------------------------}

procedure TCounter.Decrement ;

begin

{ Place code here }

end;

end.

Reversed Class Diagram from the Generated Delphi Code - counter.pas


Using With Class to Generate Delphi Code for Major O-O Relationships

To show you a more complex example, the following is the class diagram for a Car Simulation. This diagram shows all major object-oriented relationships, e.g. inheritance "type of", 1 to 1 association "knows about", 1 to 1 aggregation "part of", 1 to many association "knows about", and 1 to many aggregation "part of". This class diagram shows the Unified Modeling Language class diagram symbols: arrow - inheritance, line - association, diamond - aggregation, * - 1 to many, - private, + public, # protected, and $ static.

The diagram below shows a Car class with inheritance, association and aggregation relationships to other classes. The purpose of this example is to show a diagram with inheritance Vehicle to Car, 1:1 association Car to CellularPhone, 1:1 aggregation Car to Motor, 1:Many association Car to Passenger, and 1:Many aggregation Car to Tire.


Key points and suggested guidelines in creating the class diagram and generating Delphi code are:

- For each attribute (Delphi field), select Write_Property to generate a Write Property.

- For each attribute (Delphi field), select Read_Property to generate a Read Property.

- Capitalize all class, attribute and operation names.

- For each operation check the Procedure Checkbox for procedures. Do not check the Procedure Checkbox for functions.

- For each operation enter the operation return type and operation parameters. For each parameter enter the parameter type/class name followed by the parameter name similar to C++ form, e.g. Integer anIntegerParameter. With Class will generate the Delphi parameters, e.g. anIntegerParameter : Integer.

- For each 1:1 association, 1:1 aggregation, 1:Many association, and 1:Many aggregation, enter a relationship role name on the relationship line when you connect two classes, e.g. CurrentCellularPhone. A field is created in the TCar class, e.g. CurrentCellularPhone : CellularPhone.

The DELALL.SCT script is listed below. This is an extensive Delphi code generation script. This script reads the class diagram and creates the Vehicle.pas, Car.pas, Motor.pas, CellularPhone.pas, Passenger.pas, and Tire.pas Delphi code files. Key points about this script:

- T is prefixed to each class name, e.g. Car on the diagram becomes TCar class in the generated code.

- F is prefixes to each attribute name, e.g. Speed on the diagram becomes FSpeed in the generated code as a private Delphi field name. Protected Get function and Set procedure are generated.

- If the Read or Write property box is checked then a property is created, e.g. Speed on the diagram causes a property to be created, e.g. property Speed : Integer read GetSpeed;

- Visibility (Private/Public/Protected/Published/Automated) is based upon the specified visibility of attributes (Delphi fields) and operations (Delphi methods).

- 1 to 1 Association "knows about" is implemented by creating a Delphi field but no object is created. This means that the caller must new and free the 1:1 association object. For example, the 1:1 association between Car and CellularPhone is implemented with the Delphi field in the TCar class - currentCellularPhone : TCellularPhone. For each 1:1 association object, a Get function and Set and Remove procedures are created.

- 1 to 1 Aggregation "part of" is implemented by creating a Delphi field and creating an object. This means the assembly object does a new and free on the aggregation part object. For example, the 1:1 aggregation between Car and Motor is implemented with the Delphi field in the TCar class - currentMotor : TMotor. Since aggregation implies completely hidden part objects, no Get functions or Set procedures are created.

- 1 to Many Association relationship "knows about" is implemented as a TList collection. For example, the 1:1 association between Car and Passenger is implemented with the Delphi field in the TCar class - currentPassengers : TList. For each 1:M association object, a Public Add procedure is created - AddPassenger (aPassenger : TPassenger). For each 1:M association object, a Public Remove procedure is created - RemovePassenger (aPassenger : TPassenger).

- 1 to Many Aggregation relationship "part of" is implemented as a TList collection. For example, the 1:1 aggregation between Car and Tire is implemented with the Delphi field in the TCar class - currentTires : TList. Since aggregation implies completely hidden part objects, no Add and Remove procedures are created. The assembly object does a new and free on the aggregation part object.

- In the Create constructor attributes (Delphi fields) are initialized. 1 to 1 association objects are set to nil. List objects and aggregation part objects are created with new.

- A Destroy destructor is created. List objects and aggregation part objects are destroyed with free. Nothing is done with association objects since they must be freed in the caller.

- Uses statement is generated including unit names for Inheritance - Ancestor Classes, 1 to 1 Association, 1 to 1 Aggregation, 1 to Many Association, and 1 to Many Aggregation, e.g. uses SysUtils, Messages, Classes , Vehicle , CellularPhone, Motor, Passenger, Tire;

Script to Generate Delphi Code - DELALL.SCT

CLASS_USER1

unit CLASS_NAME;

interface

CLASS_USER2

CLASS_USER3

uses SysUtils, Messages, Classes [,DELETE_LAST_SYMBOL BASE_CLASS ] [,DELETE_LAST_SYMBOL ASSOCIATION_ONE_CLASS ][,DELETE_LAST_SYMBOL AGGREGATION_ONE_CLASS ][,DELETE_LAST_SYMBOL ASSOCIATION_MANY_CLASS ][,DELETE_LAST_SYMBOL AGGREGATION_MANY_CLASS ][,DELETE_LAST_SYMBOL INCLUDE_FILE ] ;

type

T$CLASS_NAME = class [(T$BASE_CLASS)]

private

SELECT_WHEN ATTRIBUTE_ACCESS == private [COLUMN_TAB(4) F$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ; ]

[COLUMN_TAB(4) ASSOCIATION_ONE_NAME : T$ASSOCIATION_ONE_CLASS ; {1:1 Association Field }]

[COLUMN_TAB(4) AGGREGATION_ONE_NAME : T$AGGREGATION_ONE_CLASS ; {1:1 Aggregation Part Field}]

[COLUMN_TAB(4) ASSOCIATION_MANY_NAME : TList ; {1:Many Association Field} ]

[COLUMN_TAB(4) AGGREGATION_MANY_NAME : TList ; {1:Many Aggregation Part Field} ]

SELECT_WHEN OPERATION_ACCESS == private LOGICAL_AND OPERATION_IS_PROCEDURE [

procedure OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE PASCAL_OPERATION_MESSAGE]

SELECT_WHEN OPERATION_ACCESS == private LOGICAL_AND OPERATION_IS_FUNCTION [

function OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE]

protected

SELECT_WHEN ATTRIBUTE_ACCESS == protected

[COLUMN_TAB(4) F$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ; ]

SELECT_WHEN OPERATION_ACCESS == protected LOGICAL_AND OPERATION_IS_PROCEDURE [

procedure OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE PASCAL_OPERATION_MESSAGE]

SELECT_WHEN OPERATION_ACCESS == protected LOGICAL_AND OPERATION_IS_FUNCTION [

function OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE]

[ function Get$ATTRIBUTE_NAME : ATTRIBUTE_TYPE; {Get Accessor Function }]

[ procedure Set$ATTRIBUTE_NAME ( a$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ); {Set Accessor Procedure }]

published

SELECT_WHEN ATTRIBUTE_ACCESS == published [COLUMN_TAB(4) F$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ; ]

SELECT_WHEN OPERATION_ACCESS == published LOGICAL_AND OPERATION_IS_PROCEDURE [

procedure OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE PASCAL_OPERATION_MESSAGE]

SELECT_WHEN OPERATION_ACCESS == published LOGICAL_AND OPERATION_IS_FUNCTION [

function OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE]

public

SELECT_WHEN ATTRIBUTE_ACCESS == public [COLUMN_TAB(4) F$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ; ]

SELECT_WHEN OPERATION_ACCESS == public LOGICAL_AND OPERATION_IS_PROCEDURE [

procedure OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE PASCAL_OPERATION_MESSAGE]

SELECT_WHEN OPERATION_ACCESS == public LOGICAL_AND OPERATION_IS_FUNCTION [

function OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ; PASCAL_OPERATION_VIRTUAL PASCAL_OPERATION_ABSTRACT PASCAL_OPERATION_OVERRIDE]

constructor Create; virtual; { override; replace virtual with override in derived classes }

{Update to initialize ancestor fields.}

constructor Initialize ( [a$ATTRIBUTE_NAME : ATTRIBUTE_TYPE DELETE_LAST_SYMBOL;] NO_RETURN);

destructor Destroy ; override;

function EqualTo ( a$CLASS_NAME : T$CLASS_NAME ) : Boolean ;

SELECT_WHEN ATTRIBUTE_IS_READ_PROPERTY LOGICAL_AND ATTRIBUTE_IS_WRITE_PROPERTY [

property ATTRIBUTE_NAME : ATTRIBUTE_TYPE read Get$ATTRIBUTE_NAME write Set$ATTRIBUTE_NAME ;]

SELECT_WHEN ATTRIBUTE_IS_READ_PROPERTY LOGICAL_AND LOGICAL_NOT ATTRIBUTE_IS_WRITE_PROPERTY [

property ATTRIBUTE_NAME : ATTRIBUTE_TYPE read Get$ATTRIBUTE_NAME;]

SELECT_WHEN ATTRIBUTE_IS_WRITE_PROPERTY LOGICAL_AND LOGICAL_NOT ATTRIBUTE_IS_READ_PROPERTY [

property ATTRIBUTE_NAME : ATTRIBUTE_TYPE write Set$ATTRIBUTE_NAME ;]

[ procedure Set$ASSOCIATION_ONE_CLASS ( a$ASSOCIATION_ONE_CLASS : T$ASSOCIATION_ONE_CLASS ) ; {Set Accessor Procedure for 1:1 Association}]

[ function Get$ASSOCIATION_ONE_CLASS : T$ASSOCIATION_ONE_CLASS ; {Get Assessor Function for 1:1 Association} ]

[ procedure Remove$ASSOCIATION_ONE_CLASS ;]

[ procedure Set$ASSOCIATION_MANY_CLASS$List ( a$ASSOCIATION_MANY_CLASS$List : TList ) ; {Set Accessor Procedure for 1:Many Association}]

[ function Get$ASSOCIATION_MANY_CLASS$List : TList ;{Get Assessor Function for 1:Many Association} ]

[ procedure Add$ASSOCIATION_MANY_CLASS ( a$ASSOCIATION_MANY_CLASS : T$ASSOCIATION_MANY_CLASS ) ;]

[ function Get$ASSOCIATION_MANY_CLASS ( Index : Integer ) : T$ASSOCIATION_MANY_CLASS ;{Get Assessor Function for 1:Many Association}]

[ function Get$ASSOCIATION_MANY_CLASS$Count : Integer ;]

[ procedure Remove$ASSOCIATION_MANY_CLASS ( a$ASSOCIATION_MANY_CLASS : T$ASSOCIATION_MANY_CLASS ) ;]

[ procedure RemoveAll$ASSOCIATION_MANY_CLASS;]

end;

implementation

{-----------------------------------------------------------------------------------------------}

constructor T$CLASS_NAME$.Create; {Association Objects Must be Created by Caller}

[NO_REPEAT var

AGGREGATION_MANY_NAME$Index : Integer;]

begin

inherited Create ;

[ F$ATTRIBUTE_NAME := ATTRIBUTE_INITIAL_VALUE; ]

[ ASSOCIATION_ONE_NAME := nil; {Caller must create ASSOCIATION_ONE_CLASS } ]

[ AGGREGATION_ONE_NAME := T$AGGREGATION_ONE_CLASS$.Create;{Create 1:1 Aggregation Part Object}]

[ ASSOCIATION_MANY_NAME := TList$.Create;{Create List Object for 1:1 Association Objects} ]

[ AGGREGATION_MANY_NAME := TList$.Create; {Create List Object for 1:1 Aggregation Part Objects}

for AGGREGATION_MANY_NAME$Index := 1 to 2 do {Update 2 with the number of AGGREGATION_MANY_CLASS$'s }

AGGREGATION_MANY_NAME.Add (T$AGGREGATION_MANY_CLASS$.Create);{Create AGGREGATION_MANY_CLASS objects}]

end;

{-----------------------------------------------------------------------------------------------}

{Update to initialize ancestor fields.}

constructor T$CLASS_NAME$.Initialize ( [a$ATTRIBUTE_NAME : ATTRIBUTE_TYPE DELETE_LAST_SYMBOL;] NO_RETURN);

[NO_REPEAT var

AGGREGATION_MANY_NAME$Index : Integer;]

begin

inherited Create; {Update for inherited Initialize with Arguments}

[ F$ATTRIBUTE_NAME := a$ATTRIBUTE_NAME;]

[ ASSOCIATION_ONE_NAME := nil; {Caller must create ASSOCIATION_ONE_CLASS } ]

[ AGGREGATION_ONE_NAME := T$AGGREGATION_ONE_CLASS$.Create;{Create 1:1 Aggregation Part Object}]

[ ASSOCIATION_MANY_NAME := TList$.Create;{Create List Object for 1:1 Association Objects} ]

[ AGGREGATION_MANY_NAME := TList$.Create; {Create List Object for 1:1 Aggregation Part Objects}

for AGGREGATION_MANY_NAME$Index := 1 to 2 do {Update 2 with the number of AGGREGATION_MANY_CLASS$'s }

AGGREGATION_MANY_NAME.Add (T$AGGREGATION_MANY_CLASS$.Create);{Create AGGREGATION_MANY_CLASS objects}]

end;

{-----------------------------------------------------------------------------------------------}

destructor T$CLASS_NAME$.Destroy ;

[NO_REPEAT var

AGGREGATION_MANY_NAME$Index : Integer;

Temp$AGGREGATION_MANY_NAME : T$AGGREGATION_MANY_CLASS ; ]

begin

[ AGGREGATION_ONE_NAME$.Free; {Frees 1:1 Aggregation Part Object} ]

[ ASSOCIATION_MANY_NAME$.Free; {Frees 1:Many Association List-caller must free Association objects} ]

[ for AGGREGATION_MANY_NAME$Index := 1 to AGGREGATION_MANY_NAME$.Count do

begin

Temp$AGGREGATION_MANY_NAME := AGGREGATION_MANY_NAME$.Items LITERAL_SYMBOL[ AGGREGATION_MANY_NAME$Index LITERAL_SYMBOL] ;

Temp$AGGREGATION_MANY_NAME.Free; {Frees 1:Many Aggregation Part Objects}

end;

AGGREGATION_MANY_NAME$.Free;{Frees 1:Many Aggregation List Object} ]

inherited Destroy;

end;

{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME.EqualTo ( a$CLASS_NAME : T$CLASS_NAME ) : Boolean;

begin { Does a field by field comparison - update to compare ancestor fields }

EqualTo := True;

[if (F$ATTRIBUTE_NAME <> a$CLASS_NAME.F$ATTRIBUTE_NAME) then EqualTo := False ;]

end;

SELECT_WHEN OPERATION_IS_PROCEDURE

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME.OPERATION_NAME PASCAL_OPERATION_PARAMETERS_WITH_VAR ;

begin

{ Place code here }

OPERATION_CODE

end;

]

SELECT_WHEN OPERATION_IS_FUNCTION

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME.OPERATION_NAME PASCAL_OPERATION_PARAMETERS PASCAL_OPERATION_RETURN_TYPE ;

begin

{ Place code here and return an object }

OPERATION_CODE

end;

]

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME.Get$ATTRIBUTE_NAME : ATTRIBUTE_TYPE; {Accessor Get Function }

begin

Get$ATTRIBUTE_NAME := F$ATTRIBUTE_NAME;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME.Set$ATTRIBUTE_NAME ( a$ATTRIBUTE_NAME : ATTRIBUTE_TYPE ); {Accessor Set Procedure }

begin

F$ATTRIBUTE_NAME := a$ATTRIBUTE_NAME;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.Set$ASSOCIATION_ONE_CLASS ( a$ASSOCIATION_ONE_CLASS : T$ASSOCIATION_ONE_CLASS );

begin

ASSOCIATION_ONE_NAME := a$ASSOCIATION_ONE_CLASS ;

end;

]

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME$.Get$ASSOCIATION_ONE_CLASS ( ) : T$ASSOCIATION_ONE_CLASS ;

begin

Get$ASSOCIATION_ONE_CLASS := ASSOCIATION_ONE_NAME;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.Remove$ASSOCIATION_ONE_CLASS ;

begin

ASSOCIATION_ONE_NAME := nil;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.Set$ASSOCIATION_MANY_CLASS$List ( a$ASSOCIATION_MANY_CLASS$List : TList );

begin

ASSOCIATION_MANY_NAME := a$ASSOCIATION_MANY_CLASS$List ;

end;

]

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME$.Get$ASSOCIATION_MANY_CLASS$List ( ) : TList ;

begin

Get$ASSOCIATION_MANY_CLASS$List := ASSOCIATION_MANY_NAME;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.Add$ASSOCIATION_MANY_CLASS ( a$ASSOCIATION_MANY_CLASS : T$ASSOCIATION_MANY_CLASS );

begin {Caller must create a$ASSOCIATION_MANY_CLASS }

ASSOCIATION_MANY_NAME.Add (a$ASSOCIATION_MANY_CLASS) ;

end;

]

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME$.Get$ASSOCIATION_MANY_CLASS (Index : Integer ) : T$ASSOCIATION_MANY_CLASS ;

begin

Get$ASSOCIATION_MANY_CLASS := ASSOCIATION_MANY_NAME.Items LITERAL_SYMBOL[Index LITERAL_SYMBOL];

end;

]

[{-----------------------------------------------------------------------------------------------}

function T$CLASS_NAME$.Get$ASSOCIATION_MANY_CLASS$Count : Integer ;

begin

Get$ASSOCIATION_MANY_CLASS$Count := ASSOCIATION_MANY_NAME.Count;

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.Remove$ASSOCIATION_MANY_CLASS ( a$ASSOCIATION_MANY_CLASS : T$ASSOCIATION_MANY_CLASS );

begin { Caller must free a$ASSOCIATION_MANY_CLASS }

ASSOCIATION_MANY_NAME.Remove (a$ASSOCIATION_MANY_CLASS) ; {Caller must free a$ASSOCIATION_MANY_CLASS }

end;

]

[{-----------------------------------------------------------------------------------------------}

procedure T$CLASS_NAME$.RemoveAll$ASSOCIATION_MANY_CLASS ;

begin { Caller must free ASSOCIATION_MANY_CLASS$'s }

ASSOCIATION_MANY_NAME.Clear;

end;

]

end.

Generated Delphi Code for the Car Unit Using DELALL.SCT

unit Car;

interface

uses SysUtils, Messages, Classes , Vehicle , CellularPhone, Motor, Passenger, Tire;

type

TCar = class (TVehicle)

private

FSpeed : Integer ;

FGasQuantity : Integer ;

CurrentCellularPhone : TCellularPhone ; {1:1 Association Field }

CurrentMotor : TMotor ; {1:1 Aggregation Part Field}

CurrentPassengers : TList ; {1:Many Association Field}

CurrentTires : TList ; {1:Many Aggregation Part Field}

protected

function GetSpeed : Integer; {Get Accessor Function }

function GetGasQuantity : Integer; {Get Accessor Function }

procedure SetSpeed ( aSpeed : Integer ); {Set Accessor Procedure }

procedure SetGasQuantity ( aGasQuantity : Integer ); {Set Accessor Procedure }

published

public

procedure Start ; override;

procedure Operate (A_Speed : Integer; A_Number : Integer; var The_Integer : Integer) ;

procedure Stop ;

procedure MakePhoneCall ;

procedure ReceivePhoneCall ;

procedure RegisterIt ; override;

constructor Create; virtual;

{ override; replace virtual with override in derived classes }

{Update to initialize ancestor fields.}

constructor Initialize ( aSpeed : Integer ; aGasQuantity : Integer );

destructor Destroy ; override;

function EqualTo ( aCar : TCar ) : Boolean ;

property Speed : Integer read GetSpeed;

property GasQuantity : Integer read GetGasQuantity;

procedure SetCellularPhone ( aCellularPhone : TCellularPhone ) ;

{Set Accessor Procedure for 1:1 Association}

function GetCellularPhone : TCellularPhone ;

{Get Assessor Function for 1:1 Association}

procedure RemoveCellularPhone ;

procedure SetPassengerList ( aPassengerList : TList ) ;

{Set Accessor Procedure for 1:Many Association}

function GetPassengerList : TList ;

{Get Assessor Function for 1:Many Association}

procedure AddPassenger ( aPassenger : TPassenger ) ;

function GetPassenger ( Index : Integer ) : TPassenger ;

{Get Assessor Function for 1:Many Association}

function GetPassengerCount : Integer ;

procedure RemovePassenger ( aPassenger : TPassenger ) ;

procedure RemoveAllPassenger;

end;

implementation

{-------------------------------------------------------------------------------}

constructor TCar.Create; {Association Objects Must be Created by Caller}

var

CurrentTiresIndex : Integer;

begin

inherited Create ;

FSpeed := 0;

FGasQuantity := 0;

CurrentCellularPhone := nil; {Caller must create CellularPhone }

CurrentMotor := TMotor.Create;{Create 1:1 Aggregation Part Object}

CurrentPassengers := TList.Create;

{Create List Object for 1:1 Association Objects}

CurrentTires := TList.Create;

{Create List Object for 1:1 Aggregation Part Objects}

for CurrentTiresIndex := 1 to 2 do {Update 2 with the number of Tire's }

CurrentTires.Add (TTire.Create);{Create Tire objects}

end;

{------------------------------------------------------------------------------}

{Update to initialize ancestor fields.}

constructor TCar.Initialize ( aSpeed : Integer ;

aGasQuantity : Integer );

var

CurrentTiresIndex : Integer;

begin

inherited Create; {Update for inherited Initialize with Arguments}

FSpeed := aSpeed;

FGasQuantity := aGasQuantity;

CurrentCellularPhone := nil; {Caller must create CellularPhone }

CurrentMotor := TMotor.Create;{Create 1:1 Aggregation Part Object}

CurrentPassengers := TList.Create;

{Create List Object for 1:1 Association Objects}

CurrentTires := TList.Create;

{Create List Object for 1:1 Aggregation Part Objects}

for CurrentTiresIndex := 1 to 2 do {Update 2 with the number of Tire's }

CurrentTires.Add (TTire.Create);{Create Tire objects}

end;

{-----------------------------------------------------------------------------}

destructor TCar.Destroy ;

var

CurrentTiresIndex : Integer;

TempCurrentTires : TTire ;

begin

CurrentMotor.Free; {Frees 1:1 Aggregation Part Object}

CurrentPassengers.Free;

{Frees 1:Many Association List-caller must free Association objects}

for CurrentTiresIndex := 1 to CurrentTires.Count do

begin

TempCurrentTires := CurrentTires.Items [ CurrentTiresIndex ] ;

TempCurrentTires.Free;

{Frees 1:Many Aggregation Part Objects}

end;

CurrentTires.Free;{Frees 1:Many Aggregation List Object}

inherited Destroy;

end;

{------------------------------------------------------------------------------}

function TCar.EqualTo ( aCar : TCar ) : Boolean;

begin { Does a field by field comparison - update to compare ancestor fields }

EqualTo := True;

if (FSpeed <> aCar.FSpeed) then EqualTo := False ;

if (FGasQuantity <> aCar.FGasQuantity) then EqualTo := False ;

end;

{------------------------------------------------------------------------------}

procedure TCar.Start ;

begin

{ Place code here }

end;

{--------------------------------------------------------------------------------}

procedure TCar.Operate (A_Speed : Integer; A_Number : Integer; var The_Integer : Integer) ;

begin

{ Place code here }

end;

{------------------------------------------------------------------------------}

procedure TCar.Stop ;

begin

{ Place code here }

end;

{------------------------------------------------------------------------------}

procedure TCar.MakePhoneCall ;

begin

{ Place code here }

end;

{------------------------------------------------------------------------------}

procedure TCar.ReceivePhoneCall ;

begin

{ Place code here }

end;

{-----------------------------------------------------------------------------}

procedure TCar.RegisterIt ;

begin

{ Place code here }

end;

{------------------------------------------------------------------------------}

function TCar.GetSpeed : Integer; {Accessor Get Function }

begin

GetSpeed := FSpeed;

end;

{-----------------------------------------------------------------------------}

function TCar.GetGasQuantity : Integer; {Accessor Get Function }

begin

GetGasQuantity := FGasQuantity;

end;

{-----------------------------------------------------------------------------}

procedure TCar.SetSpeed ( aSpeed : Integer ); {Accessor Set Procedure }

begin

FSpeed := aSpeed;

end;

{-----------------------------------------------------------------------------}

procedure TCar.SetGasQuantity ( aGasQuantity : Integer ); {Accessor Set Procedure }

begin

FGasQuantity := aGasQuantity;

end;

{-----------------------------------------------------------------------------}

procedure TCar.SetCellularPhone ( aCellularPhone : TCellularPhone );

begin

CurrentCellularPhone := aCellularPhone ;

end;

{-----------------------------------------------------------------------------}

function TCar.GetCellularPhone ( ) : TCellularPhone ;

begin

GetCellularPhone := CurrentCellularPhone;

end;

{-----------------------------------------------------------------------------}

procedure TCar.RemoveCellularPhone ;

begin

CurrentCellularPhone := nil;

end;

{-----------------------------------------------------------------------------}

procedure TCar.SetPassengerList ( aPassengerList : TList );

begin

CurrentPassengers := aPassengerList ;

end;

{-----------------------------------------------------------------------------}

function TCar.GetPassengerList ( ) : TList ;

begin

GetPassengerList := CurrentPassengers;

end;

{-----------------------------------------------------------------------------}

procedure TCar.AddPassenger ( aPassenger : TPassenger );

begin {Caller must create aPassenger }

CurrentPassengers.Add (aPassenger) ;

end;

{-----------------------------------------------------------------------------}

function TCar.GetPassenger (Index : Integer ) : TPassenger ;

begin

GetPassenger := CurrentPassengers.Items [Index ];

end;

{------------------------------------------------------------------------------}

function TCar.GetPassengerCount : Integer ;

begin

GetPassengerCount := CurrentPassengers.Count;

end;

{------------------------------------------------------------------------------}

procedure TCar.RemovePassenger ( aPassenger : TPassenger );

begin { Caller must free aPassenger }

CurrentPassengers.Remove (aPassenger) ; {Caller must free aPassenger }

end;

{-------------------------------------------------------------------------------}

procedure TCar.RemoveAllPassenger ;

begin { Caller must free Passenger's }

CurrentPassengers.Clear;

end;

end.

Using With Class to Reverse Engineer Delphi Code

After you compile and update your generated Delphi code in the Delphi environment, you may reverse engineer the code into a class diagram. Select Utilities - Preferences to select Delphi. Select Utilities - Reverse Directory. Select the Delphi files to be reversed. Select OK. With Class reads the Delphi files and creates the class diagram. You may reverse any Delphi code that successfully compiles. Below is the reversed class diagram from the updated code for the Car Simulation program. This diagram shows the Unified Modeling Language graphic symbols. The trailing $ indicates an overloaded property/method name.




The following are the steps to reverse Delphi .pas files and to create the data dictionary report.

Generating Delphi from a State Diagram

You may use With Class to create a state diagram and to generate Delphi code from the state diagram. Typically, you will create a single Controller class from the state diagram with a single procedure "Process".


Script to Generate Delphi Code for the Controller Unit - DELSTAT1.SCT

NO_OUTPUT_BEGIN

State code generation for Delphi from a state diagram

1. Create the state diagram

2. Utilities - Generate State Code/Report

3. Save unit file as Controller.pas

4. Compile Controller.pas in Delphi

NO_OUTPUT_END

SCRIPT_NOREPEAT_HEADER_BEGIN

unit STATE_CLASS_NAME;

interface

uses SysUtils, Messages, Classes ;

type

States = ( [NO_RETURN STATE_LIST_NAME,DELETE_LAST_SYMBOL] ) ;

Events = ( [NO_RETURN EVENT_LIST_NAME,DELETE_LAST_SYMBOL] ) ;

T$STATE_CLASS_NAME = class [(T$BASE_CLASS)]

private

currentState : States;

public

procedure Process ( anEvent : Events ) ;

constructor Create; virtual; {change virtual to override if descendant class}

destructor Destroy; override;

end;

implementation

{-----------------------------------------------------------------------------------------------}

constructor T$STATE_CLASS_NAME$.Create;

begin

inherited Create ;

currentState := STATE_INITIAL_NAME ;

end;

{-----------------------------------------------------------------------------------------------}

{Update as required.}

destructor T$STATE_CLASS_NAME$.Destroy;

begin

inherited Destroy;

end;

{-----------------------------------------------------------------------------------------------}

{ Process procedure }

procedure T$STATE_CLASS_NAME.Process ( anEvent : Events ) ;

var

condition : Boolean;

begin

SCRIPT_NOREPEAT_HEADER_END

[

if ( currentState = TRANSITION_CURRENT_STATE ) And ( anEvent = TRANSITION_EVENT ) And ( TRANSITION_CONDITION )

then

begin

currentState := TRANSITION_NEXT_STATE ;

TRANSITION_ACTION

end;

]

SCRIPT_NOREPEAT_FOOTER_BEGIN

end;

end.

SCRIPT_NOREPEAT_FOOTER_END

Generated Delphi Code for the Controller Unit Using DELSTAT1.SCT

unit Controller;

interface

uses SysUtils, Messages, Classes ;

type

States = ( OffState, OnState, Termination ) ;

Events = ( turnOff, turnOn ) ;

TController = class

private

currentState : States;

public

procedure Process ( anEvent : Events ) ;

constructor Create; virtual; {change virtual to override if descendant class}

destructor Destroy; override;

end;

implementation

{------------------------------------------------------------------------------}

constructor TController.Create;

begin

inherited Create ;

currentState := OffState ;

end;

{------------------------------------------------------------------------------}

{Update as required.}

destructor TController.Destroy;

begin

inherited Destroy;

end;

{------------------------------------------------------------------------------}

{ Process procedure }

procedure TController.Process ( anEvent : Events ) ;

var

condition : Boolean;

begin

if ( currentState = OffState ) And ( anEvent = turnOn ) And ( True )

then

begin

currentState := OnState ;

end;

if ( currentState = OnState ) And ( anEvent = turnOff ) And ( True )

then

begin

currentState := Termination ;

end;

end;

end.

Reversed Class Diagram from Controller Unit - Controller.pas


Generating Activity Table from an Activity (State) Diagram

You may use With Class to create an activity diagram and to generate an activity table from the diagram. As presented in Unified Modeling Language, the activity diagram is a form of the state diagram. There are two forms of states: wait state and activity state. A wait state has an explicit event that causes a transition. An activity state has an implicit termination event that causes a transition upon completion of the activity . The activity diagram is used to describe the steps in a complex operation. A single activity diagram describes the algorithmic details of a single complex operation. The activity diagram and activity table are useful to code complex procedures in Delphi. To create an activity diagram in With Class, use the State symbol for the Activity Symbol and enter conditions and actions. In Delphi an activity may be a single statement, a group of statements, a procedure, or a function. A condition is an if..then statement. An action is statement or a message.

Simplified Activity Diagram for TCar::Start


Script to Generate Activity Table from an Activity (State) Diagram

SCRIPT_NOREPEAT_HEADER_BEGIN

Activity Name,Transition Condition,Transition Action,Transition Next Activity SCRIPT_NOREPEAT_HEADER_END

[TRANSITION_CURRENT_STATE,TRANSITION_CONDITION,TRANSITION_ACTION,TRANSITION_NEXT_STATE ]

Activity Table

Activity Name Transition ConditionTransition Action Transition Next Activity
CheckGasQuantityGasQuantity > 0 Motor1.Start();

User.ShowStatus('Car Started');

Termination
CheckGasQuantityGasQuantity <= 0 ProcessException
ProcessExceptionUser.ShowStatus('Error'); Termination

Generating Message Table from an Object Interaction Diagram

You may use With Class to create an object interaction diagram (sequence diagram) and to generate Delphi messages from the diagram.

Object Interaction (Sequence) Diagram


Script to Generate Message Table - TABOBMSG.SCT

SCRIPT_NOREPEAT_HEADER_BEGIN

Sequence #, Sender System/Class::Object, Sender Operation, Return Type, Receiver System/Class::Object, Invoked Operation (Parameters) SCRIPT_NOREPEAT_HEADER_END

[INTERACTION_SEQUENCE_NUMBER, INTERACTION_SENDER_CLASS_NAME::INTERACTION_SENDER_OBJECT_NAME, INTERACTION_SENDER_OPERATION_NAME, INTERACTION_OPERATION_RETURN_TYPE, INTERACTION_RECEIVER_CLASS_NAME::INTERACTION_RECEIVER_OBJECT_NAME, INTERACTION_OPERATION_NAME (INTERACTION_OPERATION_PARAMETERS)]

Message Table - Generated Information Placed into a Table

Sequence #Sender System/Class::Object Sender OperationReturn Type Receiver System/Class::ObjectInvoked Operation (Parameters)
1User::User TCar::Car1Start ()
2TCar::Car1TCar::Start TMotor::Motor1Start ()
3TCar::Car1TCar::Start User::UserShowStatus ()

Summary Guidelines to Use With Class to Develop Delphi Applications

The following are some guidelines to create diagrams and to generate Delphi code.

- Select Utilities - Preferences select Delphi as the language. Enter Delphi types if desired.

- Enter class information in the Class Specification.

- Enter attribute information in the Attribute Specification.

- Enter operation information in the Operation Specification.

- To generate Delphi code, select a Delphi script, e.g. DELBASIC.SCT.

- After changing the Delphi code, import the changed code from the Operation Specification - Code Form.

- To create a class diagram from existing Delphi code, select Utilities - Reverse Directory.

- Additionally, Delphi code may be generated from a state diagram with the script DELSTAT1.SCT and a Delphi message table may be generated from an object interaction diagram with the script TABOBMSG.SCT.

Comments and suggestions on this tutorial and the Delphi code generation scripts are requested - Richard Felsinger RCF Associates, 960 Scottland Dr, Mt Pleasant, SC 29464 Telephone 803-881-3648 e-mail 71162.755@compuserve.com Comprehensive O-O Model Building and C++/Java/Delphi Development and Training Available.

free cialis submit=free cialis cialis com cialis order java.js buy cheap cialis online cialis exchange link cialis tadalafil american express viagra cialis buy cialis link mycialsnowprohostingcom onlinehtml cialis impotence drug eli lilly co cialis without prescription in detroit area why cialis buy cialis link onlinehtm pharmacyrxfreewebtoolscom cialis in south africa do u take cialis everyday add cialis url cialis and manufacturer cialis muncie indiana how to stop viagra cialis spam black buy casino cialis diet followup gambling jack low online order phentermine poker post viagra cialis comparison levitra cialis online sales mexican cialis boelolokeepkidshealthycom cialis link cialis day next cialis purchase mixing cialis with effexor bulk cialis and viagra sold world wide on line cialis discount save cialis story safest of cialis levitra viagra buy cialis href newopasblogdrivecom cialis en venezuela cialis western open tee times viagra and cialis cheap buy cialis link onlinecolnu cialis europe viagra cialis submit=cialis should i buy cialis online buy cialis amsterdam cialis dose cialis tablet sildenafil cialis generico buy cialis cialisfunsurforg onlinehtml cialis drug impotence cialis testimonials sitemap1 buy cialis no prescription cialis for order cialis side effects order cialis buy cialis dreampharmaceuticals cialis drug cialis peak serum time half life pill cutters for cialis blindness cialis cialis dysfunction erectile cialis pill low cost generic cialis blogid buy casino cialis inurl order phentermine poker viagra cialis compare viagra cialis soft tabs den haag results of comparisons of viagra and cialis buy cialis in uk cialis en espanol cialis prescriptions map buy cheap cialis cialis link onlineinfo cialis cost low cialis online sale mixing viagra and cialis black buy casino cialis diet followup gambling jack order phentermine poker viagra cialis cheapest online prices cialis news information about cialis and livetra black buy casino cialis diet gambling jack online order phentermine poker tag viagra xhtml cialis class action suit cialis open ticket western order cialis online black buy casino cialis diet holdem jack online order phentermine poker tag texas viagra xhtml cialis comment info personal remember cialis order in south africa is cialis over the counter drug black casino cialis diet followup gambling health jack phentermine poker viagra cialis company cialis on line generic soft tab cialis better erections by combining cialis and viagra cialis attorney ohio cialis melt tabs how does cialis work black buy casino cheap cialis diet followup gambling health jack online order phentermine poker viagra cialis black box warnings cialis mexico online how to get best results with cialis archive buy cialis cialis discount generic cialis online purchase how viagra cialis levitra work black buy casino cialis diet followup gambling jack online order phentermine poker viagra cialis cedar park cialis mg index best cialis generic price cialis and no prescription required cialis link pharmacyrawcsorg generic cialis online best place to get totally free viagra or cialis samples cialis and venous leak