Vous êtes sur la page 1sur 37

Chapter 1

Introduction to OO basics

Main concepts
Introducing: Object orientation basics Unit structure and project structure Delphis RAD generation: visual objects and events Event handlers Creating an object (RAD and coding) Defining a class Declaring an object reference Instantiating an object Freeing an object Interaction between objects: simple message passing, association and composition The UML: class, object and sequence diagrams Inheritance, association and composition relationships

Chapter contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Object orientations basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Representing OO systems: the UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Introduction to OO basics (31 May 2006, all rights reserved) Chapter 1, Page 1

Patterns: applying OO principles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Learning OO programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Delphi as a learning environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Example 1.1 A unit file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 The unit name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 The interface section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 The implementation section . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Example 1.2 Extending an empty application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Ex 1.2 step 1 A RAD GUI builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Ex 1.2 step 2 Events and their handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Ex 1.2 step 3 Analysing the RAD-generated code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Ex 1.2 step 4 A graphical representation: the UML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Example 1.3 Object interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Ex 1.3 step 1 A main form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Ex 1.3 step 2 An auxiliary form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Ex 1.3 step 3 The project file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Ex 1.3 step 4 A matching UML class diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Ex 1.3 step 5 A matching UML object diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Ex 1.3 step 6 A matching UML sequence diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Ex 1.3 step 7 Explicit Create and Free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Ex 1.3 step 8 Lifetimes in a sequence diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Example 1.4 Defining a form directly in code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Ex 1.4 step 1 Modifying the previous program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Ex 1.4 step 2 Methods, and event handler linking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Ex 1.4 step 3 Matching UML diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

Introduction
Object orientations basics
Object Orientation (OO) can be seen from three different aspects: objects as independent entities, objects as derived entities, and objects as interacting entities.

Chapter 1, Page 2

Object orientation with Delphi (all rights reserved)

Objects as independent entities An object is a separate, self-contained, encapsulated entity, and the term encapsulation is important in OO. This means that an object has data that it can keep private from the outside world and that it has specific behaviour. It manipulates its data and implements its behaviour through its methods. Writing the code that defines an objects methods has many similarities with structured programming, and so uses many structured programming principles such as structured selection (If..then..else, Case) and repetition (While..do and For loops). In this module we assume that students are familiar with these concepts and so concentrate on principles that apply specifically to OO programming. Objects as derived entities Reuse is a very important consideration in OO programming. If some required operations or data storage already exist in one class, it is possible for another class to take advantage of these operations and data and so avoid recoding them. OO makes this second aspect, a classs derivation from other classes, possible through subclassing (using inheritance) and through composition, and can significantly reduce the amount of code one needs to write. Objects as interacting entities The third aspect, the interaction between objects, depends on association and subtyping. If objects could not interact, they could not cooperate with each other to perform the various tasks required in a computer program. So the programmer creates associations (links) between objects to provide pathways for objects to send messages to one another. To allow these interactions to lead to different results under different circumstances, the programmer can use subtyping and polymorphism. Subtyping is when objects within the same hierarchy implement their common interface differently and is an important focus later in this module. There is considerable interleaving between these aspects. Object derivation and object interaction both use inheritance, which is directly supported in the programming language, and forms of object linking (association and composition), which are not directly supported by language constructs.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 3

Representing OO systems: the UML


It is useful to be able to represent a program in a compact, graphical way as an alternative to the actual code. This module uses a subset of the Unified Modelling Language (UML). The UML provides an integrated and standard set of diagrams that are widely used. In this module we concentrate on class, object and sequence diagrams to capture the static and dynamic aspects of the programs and to present the underlying OO principles.

Patterns: applying OO principles


While the basic OO principles are quite simple, their application can become extremely sophisticated. Members of the OO community has adopted the concept of Software Patterns to capture this expertise, combining the experience of many experienced OO programmers. This module takes the student through several important Software Patterns, using them to solve specific problems and to see how best to apply general OO principles.

Learning OO programming
Programming is difficult and OO programming is even more so! A common approach is to provide learners with a set of preconstructed classes (eg a graphics toolbox) as a starting point for OO programming. This module adopts a variation on this approach by using Delphi, a RAD GUI (Rapid Application Development, Graphical User Interface) generator with an extensive library of GUI components. This library allows learners to construct their own visual objects to use and manipulate in their programs. This standard library of user interface objects and the visual (GUI) code generation environment provides a natural vehicle for demonstrating underlying principles and for concretising OO concepts and a good entry point into the complexities of OO programming. It helps to clarify issues like the anatomy of a class, the combination of existing classes to create a new class, and reuse through inheritance by taking advantage of features such as the Visual Component Library (VCL) and Visual Form Inheritance (VFI)). The first chapter uses Delphis GUI generator to start looking at the internal structure of an object. The second chapter looks at RAD-generated inheritance and at the hierarchy of standard user interface components. The third chapter helps the novice OO programmer to write programmer generated classes and the fourth chapter looks at ways of accessing an object and its data. Chapter two introduces inheritance for reuse through subclassing by presenting VFI and the VCL library supplied with Delphi. Inheritance also provides the possibility of subtyping

Chapter 1, Page 4

Object orientation with Delphi (all rights reserved)

and the power of polymorphism and this is introduced in chapters four and five, using Delphis standard Sender parameter as a starting point. Chapter six draws together the material from the preceding chapters by stating several anti-patterns that highlight potential pitfalls in using inheritance. Along with polymorphism, the concept of cooperating objects is crucial to OO. Object cooperation in various forms is a theme running from chapter seven through to the end of the module. The concepts of polymorphism and cooperation are consolidated by the exploration, from chapter nine onwards, of a variety of OO patterns. The following table shows the patterns well cover in this module along with the OO programming concepts these patterns allow us to explore:

Pattern Immutable

Concepts Encapsulation and visibility (private, protected and public fields)

Sender Argument

Low coupling Callbacks

Adapter

Reuse Implicit delegation Enabling substitution with unrelated class

Facade

Low coupling Implicit delegation Packaging for simplification

Law of Demeter

Low coupling Implicit delegation

Player-Role

Class definition, distinguishing between attributes and roles Delegation Packaging for future evolution Changing associations dynamically

Strategy

Packaging for variability (reducing coupling) Polymorphic substitution

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 5

Template method

Packaging for variability (reducing coupling) Polymorphic substitution Implementation at different hierarchical levels

Association class

Class definition Link (association) information

Factory method and Abstract Factory Singleton Mono State Decorator

Object manufacture Separation of concerns Object manufacture Class and object data fields Polymorphic recursion

While contrasting subclassing and subtyping we also consider several inheritance antipatterns. The fundamental principles of patterns are presented textually and graphically (through words and UML class diagrams, object diagrams and sequence diagrams) and the implementation through detailed worked examples, allowing the student to consolidate the concepts by considering two different perspectives. Using these diagrams brings familiarity in reading class, object and sequence diagrams. This helps develop representational literacy and indicates some of their strengths and limitations.

Delphi as a learning environment


This module uses Delphi to teach object orientation. Delphis roots lie in Pascal, and so it has a sound, structured foundation. It is also strongly object oriented and provides many OO characteristics such as class inheritance, static binding and dynamic binding, and reference semantics. The module makes extensive use of graded, worked examples to give students hands-on experience in the implementation of OO code. This helps to bridge the gap between the seemingly simple OO principles and the ramifications of these principles in practice. Through the inductive sequencing of concepts and through the extensive use of worked examples, this module strongly supports independent study, and has been prepared with distance learning students in mind. In the first two chapters of this module we use Delphis RAD facilities to start exploring various aspects of OO. Then we apply these same principles to code that we ourselves write. We start exploring how to define and instantiate classes by looking at the way Delphi builds

Chapter 1, Page 6

Object orientation with Delphi (all rights reserved)

up a Form, which is the name Delphi uses for a window in a graphical interface environment.

Example 1.1 A unit file


Delphi is structured around the concept of objects. A form is an object and the various Components we place on a form are also objects. To start investigating Delphis RAD classes and objects, open a new application (File | New | Application up to Delphi 7; File | New | VCL Forms Application1 in Delphi 8). Using the menu sequence View | Units | Unit1, look at the code for Unit1. Different versions of Delphi differ slightly: version 7 looks like this:
1 unit Unit1; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs; 6 type 7 TForm1 = class(TForm) 8 private 9 { Private declarations } 10 public 11 { Public declarations } 12 end; 13 var 14 Form1: TForm1; 15 implementation 16 {$R *.dfm} 17 end.

Delphi programs can contain many unit files. The basic structure of a unit file comprises three sections, the unit name (as in line 1 above), the interface section (lines 214) and the implementation section (lines 1517).

Delphi 8 offers a choice of VCL Forms (which gives backward compatibility with earlier versions), W indows Forms and ASP .NET. Since the OO principles we are working with are effectively independent of which of these you use, we use VCL Forms to make it easier to move between the different versions.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 7

The unit name


By default, Delphi assigns the first unit the name Unit1 (line 1). It calls subsequent units Unit2, Unit3. and so on. When we save the file under a new name (eg with the File | Save As ... menu sequence), Delphi changes the units name and maintains a cross reference to this file in the project (.dpr or .bdsproj) file. (More of this later.)

The interface section


The interface section (lines 214) provides the link between a particular unit and other units and consists of several subsections: the uses clause (lines 35), the type declarations (lines 612) and the global variable declarations (lines 1314). (Global constant declarations, which we dont have here, are similar to global variable declarations.) The uses clause (lines 35): In order to run, a Delphi program needs a lot of background information from various unit files that are a standard part of Delphi. For instance, if the file SysUtils (line 4) were not in the uses list, we would not be able to do any string operations. As part of its RAD support, Delphi automatically lists the additional units the user interface needs under the uses clause. We wont discuss these individual units in detail, but its easy to find out more about them: in the editor, place the cursor on one of the names and then press <F1> for Help. The type declaration (lines 612): In object oriented programming languages, a type or class2 defines a structure or template that we can use in our program to create (instantiate) an object we need. Here we are defining a user interface class and Delphi generates the code for the form class automatically through its RAD capability. Well use this RAD generated code as an example later, when we define our own classes. Line 6 in Delphis RAD code above notifies the compiler that the type (class) declarations follow. In this program we declare only one class, TForm1, but we can declare additional classes as well either in the same unit or in different units. Line 7 derives a new class, called TForm1, from TForm. TForm is a standard Delphi class and is the template for the blank form that appears when we start a new application. The standard TForm class has a lot of capability built into it. For instance, it knows (through its methods) how to create itself and how to show itself on the screen. It also has properties like a Caption, a Height and a Width. Because of line 7 we inherit all this capability from TForm as a starting point for our own class, TForm1. At the moment we still have only the

The words type and a class are closely related, and well go into the differences between these two terms later on in this module.

Chapter 1, Page 8

Object orientation with Delphi (all rights reserved)

unadorned form and dont extend it in any way. In a little while, when we add some Components and event handlers, we will see how Delphi uses its RAD facility to add these objects and methods to the type declaration of TForm1. The var (variable) declaration (lines 13 & 14): The previous subsection, the type declaration, provides the additional classes that we define in our program. However, a type is a template only and not an object. In this section, the var declaration, we declare what objects we will create from the available classes. This sets aside memory on the stack for references to these objects. The only object so far is the form that Delphi creates automatically when we start a new project. It is called Form1 , and is of type TForm1 (line 14). To help us keep the distinction between the type and the object, Delphi has the convention of starting type names with a T. Thus, TForm1 is the type and Form1 is the object.

The implementation section


The third part of a unit is the implementation section. This is where we write our program code. Because we have not written any routines yet the implementation section is empty except for the compiler directive {$R *.DFM} (line 16). At first glance, the curly brackets make this compiler directive look like a comment, and so presumably we should be able to delete it. But dont be fooled! The opening symbol here is the compound symbol {$ which means that it is not a conventional comment but is instead a special instruction to the compiler. {$R *.DFM} is a resource directive and tells the compiler to include the form file (the .dfm file) in the application. So do not delete this line. An optional local uses clause and unit level constant and variable declarations, not present here, can appear followed by the necessary method definitions. (Ex 1.3 step 2, line 17 shows a local uses clause.) Unlike the interface section, which makes communication with other units possible, the implementation section is private to the unit. It describes the inner workings of all the classes declared in the type declaration. Ex 1.1 Summary: The unit file has a name for identifying itself, an interface section for communicating with other units and an implementation section giving the private details of the units functioning. The interface section contains the global uses clause, the type declaration, and the global constant and variable declarations. The implementation section contains the local uses clause, the local constant and variable declarations, and the method definitions.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 9

Delphi automatically creates a skeleton of the new TForm1 class we are creating. It uses the standard TForm class as the basis of the new TForm1 class by deriving TForm1 from TForm.

Example 1.2 Extending an empty application


Among the various RAD facilities that Delphi offers is a visual builder for graphical user interfaces (GUIs). This greatly simplifies the building of a user interface and allows the programmer to concentrate on programming. In this example we look briefly at the GUI builder process to write a program with two buttons. Clicking the one turns the form yellow, clicking the other turns the form blue (figure 1).

Ex 1.2 step 1 A RAD GUI builder


Figure 1 A simple Delphi program

Here we create a simple Delphi program and then look at the RAD generated code in the units listing. Starting with a new application, add two buttons by selecting them from the Component / Tool palette and dropping them onto the form (figure 1). To change the units name, save it as TwoButtonsU.pas (using the File | Save As menu sequence). Now initialise some properties of the GUI objects in the Object Inspector and notice how they change in the Form Designer. One way to present the properties is by means of a table:

Component Form

Property Name Caption

Value frmStructureDemo Unit Structure btnYellow &Yellow btnBlue &Blue

Button1

Name Caption

Button2

Name Caption

Chapter 1, Page 10

Object orientation with Delphi (all rights reserved)

Delphi stores the initial properties in a .dfm file. Representing this properties table in the dfm format gives the following:
object frmStructureDemo: TfrmStructureDemo Caption = ' Unit Structure' object btnYellow: TButton Caption = '&Yellow' object btnBlue: TButton Caption = '&Blue'

Delphi 6 and 7 show the structure of the user interface object in the Object TreeView (figure 2). (The Model View in Delphi 8 / 2005 gives similar functionality.) This gives the containment hierarchy, not the class inheritance hierarchy, and shows that the form object frmStructureDemo contains two buttons, btnBlue and btnYellow. (As we will explore later, Delphi implements this containment through a strong form of aggregation called composition.)
Figure 2 The Object TreeView showing the form composed from the Buttons

Ex 1.2 step 2 Events and their handlers


The GUI interacts with the program code through events. The form itself and each object on the form can give rise to a number of different events in response either to user actions or to system occurrences. One of the more common events is the OnClick event, which is generated when the user clicks with the mouse on a visual object. In this step we write event handlers for each buttons OnClick event. Double-click on btnBlue. Delphis RAD generator inserts an event-handler skeleton in the program code and links the OnClick event to this event handler. Insert the required program statement (line 27 below) and then double-click on btnYellow and insert its program statement (line 23) before saving the unit (File | Save As) as TwoButtonsU and then the project file (File | Save Project As) as TwoButtonsP. Run the program (<F9> or Run Introduction to OO basics (31 May 2006, all rights reserved) Chapter 1, Page 11

| Run). Clicking with the mouse on button Blue makes the form go blue (line 27) while button Yellow makes the form yellow (line 23).
1 unit TwoButtonsU; 2 interface 3 uses 4 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, 5 Dialogs, StdCtrls; 6 type 7 TfrmStructureDemo = class(TForm) 8 btnYellow: TButton; 9 btnPurple: TButton; 10 procedure btnYellowClick(Sender: TObject); 11 procedure btnBlueClick(Sender: TObject); 12 private 13 { Private declarations } 14 public 15 { Public declarations } 16 end; 17 var 18 frmStructureDemo: TfrmStructureDemo; 19 implementation 20 {$R *.DFM} 21 procedure TfrmStructureDemo.btnYellowClick(Sender: TObject); 22 begin 23 frmStructureDemo.Color := clYellow; 24 end; 25 procedure TfrmStructureDemo.btnBlueClick(Sender: TObject); 26 begin 27 frmStructureDemo.Color := clBlue; 28 end; 29 end.

Ex 1.2 step 3 Analysing the RAD-generated code


Well now investigate several aspects of the RAD-generated code.

Chapter 1, Page 12

Object orientation with Delphi (all rights reserved)

Changing the units name When we saved the unit as TwoButtonsU, Delphi changed the units name from Unit1 to TwoButtonsU (line 1 above). To keep the project tracking synchronised, always change a units name through Save As and dont change the name directly in the program code. Changing the forms name In the Object Inspector we changed the Forms name to frmStructureDemo. On this basis, Delphi changed the name of the new form type to TfrmStructureDemo. (It is still derived from TForm, line 7). Delphi then declared the form object as frmStructureDemo (without the T prefix) of type TfrmStructureDemo (with the T prefix) (line 18). (The variable declaration in line 18 means that we can use the name frmStructureDemo to refer to an object of type TfrmStructureDemo.) Adding buttons We added two buttons to the form and called them btnYellow and btnBlue. On this basis, Delphi automatically inserted lines 8 & 9. These declare that the TfrmStructureDemo class is composed of objects called btnYellow and btnBlue, both of type TButton (Delphis standard class for buttons). These objects are now part of the type TfrmStructureDemo as reflected in the Object TreeView (figure 2). In composing a class, in this case TfrmStructureDemo, from other objects, in this case btnYellow and btnBlue of type TButton, we automatically gain all of the TButton classs capability when we include it in our form. Like TForm, TButton is a standard Delphi class, and composition gives a powerful way of re-using existing components and classes. We will return in more detail to this concept of composition when we use it as a tool for creating our own classes. Adding event-handlers We added an OnClick event-handling method3 for each button by double-clicking on each in the Form Designer and adding the necessary code. Delphi automatically extends the class definition. It incorporates these event handlers as methods of TfrmStructureDemo by declaring these procedures in the type structure (lines 10 & 11 above). These declarations do not define what the procedures do, so Delphi also creates the skeletons for these event handlers in the implementation section (lines 21 to 28), leaving us to fill in the appropriate programming statements (lines 23 & 27). In Delphi Pascal, although methods can be either procedures or functions, event handlers are always procedures. Along with all the methods

For simplicity, an event-handler method is often called just an event handler.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 13

of the TForm and TButton classes, these event handlers are now also methods belonging to the TfrmStructureDemo class. A method declaration, as in line 10, is sometimes referred to as a method signature since it gives the method name (btnYellowClick), the type of subroutine (a procedure) and the parameter list (Sender: TObject). Once we define and use our own classes and objects we will start by mimicking Delphis RAD code.

Ex 1.2 step 4 A graphical representation: the UML


When designing and documenting a program, it can be very helpful to use a graphical representation of its structure and operation. A widely used graphical OO modelling language is the Unified Modelling Language, or UML, and that is what we will use here. The UML represents a class as a box with a number of compartments (figure 3). The top compartment gives the class name (cf line 7 in the program above). The second compartment gives the class attributes (cf lines 8&9) and the third gives the methods (cf lines 10&11).
Figure 3 A UM L class diagram

A UML class diagram can also show relationships between classes such as inheritance and association. First well look at inheritance or generalisation as it is called in UML. This is shown with an open arrow head pointing from the subclass to the superclass (figure 4, cf line 7 above). Classes can become quite complex and so one generally shows only those attributes and methods that are of interest in a particular diagram. In figure 4, we show TForm without any of its attributes or methods. Because the subclass is everything that the superclass is and more, inheritance is often called an IsA relationship.

Chapter 1, Page 14

Object orientation with Delphi (all rights reserved)

Figure 4 Inheritance (generalisation) in UML

In addition to the inheritance relationship, we can also use the UML to show the various forms of association. A strict form of association is composition. We mentioned earlier that the relationship between the form and the two buttons is composition. So, instead of the two buttons as attributes of the form as in figure 4, we can show the TButton class separately and then show that TfrmStructureDemo uses (ie is composed of) two TButtons as in figure 5. The UML representation for composition is a solid diamond at the composed class connected by a line to the class or classes that the composed class uses. Although TfrmStructureDemo is composed of two TButtons: we show the TButton class only once but include a 1:2 multiplicity on the composed link. Because we show the TButtons separately, we no longer include them within the box representing TfrmStructureDemos attributes.

Figure 5 Showing composition on a UM L class diagram

Ex 1.2 Summary: As a basis for creating our own classes in the future we have investigated how Delphi adds data fields (the buttons) and methods (the event handlers) to a class definition. The UML provides class diagrams to represent the structure of classes and the inheritance and composition between them.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 15

Example 1.3 Object interaction


Objects interact with one another, and, as well come to see through the course of this module, one way to view an object-oriented program is as a group of encapsulated objects that cooperate, through message passing, to provide a particular set of services. To demonstrate this, in this example well create two classes, each in a separate unit, with simple unidirectional message passing (steps 1 and 2 below). This linking is an example of association, with one object requesting a service from another object, and is sometimes called a UsesA relationship. In step 3 well see how Delphi packages a program that consists of more than one unit. UML diagrams provide an important way of summarising and visualising what is happening in an OO program, and steps 4, 5 and 6 present the class, object and sequence diagrams for this program. At times, object A may require a service from object B, but object B does not exist yet. Under these circumstances, object A specifically create (instantiate) object B, obtain the required services from object B, and then destroy object B when it is no longer needed. Step 7 modifies the program to give a simple illustration of this process.

Ex 1.3 step 1 A main form


To illustrate simple messages, we will create two classes, each one in its in own unit. In this step we define TfrmMain (figures 6 & 7), which sends messages to TfrmAuxiliary to Show and Hide itself (lines 24 and 28 below). TfrmAuxiliary will be defined in step 2. Because TfrmMain will use TfrmAuxiliary, unit MainForm must list unit AuxForm, the unit containing TfrmAuxiliary, in a uses clause. Here we choose to use a local uses clause (line 20).
Figure 6 The main form

Figure 7 The user interface objects comprising the main form

1 unit MainForm; 2 interface

Chapter 1, Page 16

Object orientation with Delphi (all rights reserved)

3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls; 6 type 7 TfrmMain = class(TForm) 8 radAuxShow: TRadioButton; 9 radAuxHide: TRadioButton; 10 procedure radAuxShowClick(Sender: TObject); 11 procedure radAuxHideClick(Sender: TObject); 12 private 13 { Private declarations } 14 public 15 { Public declarations } 16 end; 17 var 18 frmMain: TfrmMain; 19 implementation 20 uses AuxForm; 21 {$R *.dfm} 22 procedure TfrmMain.radAuxShowClick(Sender: TObject); 23 begin 24 frmAuxiliary.Show; 25 end; // end procedure TfrmMain.radAuxShowClick 26 procedure TfrmMain.radAuxHideClick(Sender: TObject); 27 begin 28 frmAuxiliary.Hide; 29 end; // end procedure TfrmMain.radAuxHideClick 30 end.

// end unit MainForm

The message calls appear in lines 24 and 28. They consist of the target object followed by a dot followed by a message name. (We define frmAuxiliary in the next step of this example.) Message calls look like subroutine calls (lines 24 & 28 above). The difference between the two is that message calls allow polymorphism. Polymorphism is an important aspect of OO programming that allows different objects to respond differently to the same message. This, for example, allows OO programs to respond appropriately to varying conditions without the need for hard-coding complex sets of conditional statements. Delphi automatically makes provision for public and private fields in the form (lines 12 to 15). In this example there are no additional public or private fields, and so these statements do not perform any function. They remind programmers that it is possible to add private and public declarations to a RAD form, and we will do so from time to time. However quite often we will not have any private or public declarations to add, and then we will delete these lines from our code listing to avoid cluttering up the examples. Introduction to OO basics (31 May 2006, all rights reserved) Chapter 1, Page 17

Ex 1.3 step 2 An auxiliary form


Add a second form to the project (File | New | Form in Delphi 4 to 7, File | New | VCL Form in Delphi 8). This will consist of a blank form, TfrmAuxiliary, with no other components (figure 8 & figure 9). It inherits the ability to Show and Hide itself from TForm, the library class from which all forms are derived (line 7 below). We use the OnShow event handler (lines 14 to 18) to define TfrmAuxiliarys additional behaviour: it sets the position on the screen randomly each time the form is shown (lines 16 & 17). The random number generator needs to be seeded and we choose to seed it in the initialization section (lines 1920): we could also have placed the Randomize statement in the Forms OnCreate event handler. In any unit the initialization section is optional. If present, the statements in this section run when the program starts, before any of the other program statements in that unit. It begins with the reserved word initialization and continues until the beginning of the finalization section or, if there is no finalization section, until the end of the unit. If there are several units in a project, the different initialization sections run in the order that the units appear in the project file. If a unit uses any other units, their initialization sections run before its does, with the units in the interface sections uses clause running before those in the implementation section.
Figure 8 The auxiliary form

Figure 9 Components comprising the auxiliary form 1 unit AuxForm; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls; 6 type 7 TfrmAuxiliary = class(TForm) 8 procedure FormShow(Sender: TObject); 9 end; 10 var 11 frmAuxiliary: TfrmAuxiliary; 12 implementation

Chapter 1, Page 18

Object orientation with Delphi (all rights reserved)

13 {$R *.dfm} 14 procedure TfrmAuxiliary.FormShow(Sender: TObject); 15 begin 16 Left := Random (600); 17 Top := Random (400); 18 end; // end procedure TfrmAuxiliary.FormShow 19 initialization 20 Randomize; 21 end.

// end unit AuxForm

(The screen positions and references in lines 16 & 17 refer to a low resolution screen. If you are using a higher resolution display you may want to increase these values proportionately.)

Ex 1.3 step 3 The project file


Delphi keeps track of the different units in a program through the Project file. To see the project file for this example, use View | Units | Project1.
1 program TwoUnits; 2 uses 3 Forms, 4 MainForm in 'MainForm.pas' {frmMain}, 5 AuxForm in 'AuxForm.pas' {frmAuxiliary}; 6 {$R *.res} 7 begin 8 Application.Initialize; 9 Application.CreateForm(TfrmMain, frmMain); 10 Application.CreateForm(TfrmAuxiliary, frmAuxiliary); 11 Application.Run; 12 end.

Lines 910 cause the auto-creation of the two form objects in this project.

Ex 1.3 step 4 A matching UML class diagram


The class diagram for the classes defined in unit MainForm and unit AuxForm shows both of the form classes that we derive from TForm (figure 10). Neither TfrmMain nor TfrmAux declare any additional attributes so we leave the middle compartment empty for both of these. We manipulate their Left and Top attributes in the program. These they inherit from Introduction to OO basics (31 May 2006, all rights reserved) Chapter 1, Page 19

TForm, and so we show them in the middle compartment of TForm since they are attributes. (TForm does not actually define these attributes itself but inherits them in turn from TControl, one of its superclasses. But this detail is not significant here.)
Figure 10 Class diagram for ex 1.3 steps 1 & 2

Ex 1.3 step 5 A matching UML object diagram


Class diagrams such as figure 10 are very common since they show the structure of a program. Sometimes it is also useful to have a snapshot of the state of a part of a program to show what objects exist at the moment of the snapshot and what their state (ie the values of their attributes) is. A UML object diagram has two compartments. The top compartment shows the object name and its class, all underlined to emphasise that this is an object and not a class. The second compartment lists the attributes and their values at the time of the snapshot. In this example, the program creates two objects at startup and destroys them when the program ends. frmMains values for Left and Top come from the values set in the Object Inspector and frmAuxiliarys Left and Top values are set in the OnShow event handler. There is a communication link from frmMain to frmAuxiliary, and so we have the object diagram shown in figure 11.
Figure 11 The object diagram for ex 1.3 steps 1 & 2

Because frmMain interacts with frmAuxiliary, we show an association from frmMain to frmAux. The arrows point from frmMain to the other form because frmMain knows about and uses this form (lines 20, 24 & 28 in Unit MainForm). However, frmAuxiliary has no knowledge of frmMain so there is no arrowhead frmAuxiliary to frmMain. Because this is Chapter 1, Page 20 Object orientation with Delphi (all rights reserved)

an association and not an inheritance relationship we use an open and not a closed arrow head. Association, like inheritance, is an important concept in object orientation, and both crop up throughout this module. Although objects are created from classes, object diagrams mostly look very different from their related class diagram. Figure 11, for example, shows only the actual objects that exist in the system and so does not show that these objects are derived from any superclasses: for that information we refer to the class diagram.

Ex 1.3 step 6 A matching UML sequence diagram


So far we have seen a class diagram, which shows the class structure, and an object diagram, which provides a snapshot of the state. These are both static representations of the system. A sequence diagram is a form of object diagram that we can use to show dynamic aspects of the program such as message passing and the interaction between objects (figure 12). The objects (not the classes) appear in separate boxes from left to right across the top of the page. In UML, object names are underlined and class names are not. The objects may be identified through their name and class, just their name, or just their class. Here we have the same objects as those in the object diagram. We also have the user (called an actor) who initiates the sequence by clicking on a RadioButton and so the actor also appears as one of the objects, at the left side of the diagram. Time flows from the top of the diagram downwards. A dashed line falling vertically below each object is the objects lifeline, showing the time during which the object exists. A bar superimposed over the lifeline shows an objects activation or focus of control. For this particular sequence (figure 12), both objects lifetimes extend beyond this diagram and so we do not show any object creation or destruction. In this example, frmMains radAuxShows OnClick event handler sends messages to frmAux to Show and Hide itself.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 21

Figure 12 The sequence diagram for ex 1.3 steps 1 &2

Message passing is a basic communication and synchronisation mechanism within OO. A message is an invocation of an objects method. A message is shown as an arrow from one objects activation to another. There is an association relationship between these two objects: frmMain and frmAux are both independent objects with separate lifetimes since neither Creates nor Frees the other. However, as we saw in the object diagram, frmMain uses frmAux, and so association is sometimes referred to as a UsesA relationship.

Ex 1.3 step 7 Explicit Create and Free


When we start a new application or add another form to an existing application, Delphi automatically, as part of its RAD capability, sets up the class definition of the form (eg lines 716 in step 1 (unit MainForm) and lines 79 in step 2 (unit AuxForm)), declares a reference to an object of this class (eg lines 1718 in step 1 and lines 1011 in step 2) and then constructs the object (eg lines 910 in step 3 (the project file program TwoUnits)). So, with the way Delphi (and several other languages) implements OO, there are three phases to creating an object: Define the class, Declare a reference to the object (or instance), and Create the object. The class definition is a set of instructions for creating objects, a bit like a set of manufacturing plans. The object declaration sets up a mechanism for accessing the object by

Chapter 1, Page 22

Object orientation with Delphi (all rights reserved)

creating a reference on the stack. The object constructor uses the class definition to create an object in memory (the heap). In the present version of the program Delphi takes responsibility for all these steps. Quite soon well define classes and declare and create objects in the programs we write. As a first step towards this, well intervene in the auto-create process for RAD objects and create the auxiliary form as part of a program instead of allowing Delphi to create it automatically. We can remove any of the forms in a project except the main form from the auto-create list. If we do this, Delphi will no longer auto-create those forms and the programmer must create them explicitly in program code before they can be used. (We can also choose which form will be the main form.) To avoid overwriting the current version of this code, save these two units and the project file to a new directory for this example before doing anything else. Now use the Project | Options menu sequence and select the Forms options tab. The left pane lists the auto-create forms. Select frmAuxiliary in this pane and click the single right arrow to transfer it from the auto-create list to the available forms list (figure 13). Select OK to close the Project Options window.

Figure 13 Instructing Delphi not to Auto-Create frmAuxiliary

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 23

To program our previous programs user interface for creating (and freeing) the auxiliary form, add a GroupBox to the form and then add Create and Free buttons to the GroupBox (figure 14 and figure 15).
Figure 14 Creating and freeing a user interface object explicitly

Figure 15 Objects on the modified main form

Change unit MainForm to the following:


1 unit MainForm; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls; 6 type 7 TfrmMain = class(TForm) 8 radAuxShow: TRadioButton; 9 radAuxHide: TRadioButton; 10 gpbAuxiliary: TGroupBox; 11 btnCreate: TButton; 12 btnFree: TButton; 13 procedure radAuxShowClick(Sender: TObject); 14 procedure radAuxHideClick(Sender: TObject); 15 procedure btnCreateClick(Sender: TObject); 16 procedure btnFreeClick(Sender: TObject); 17 end; // end TfrmMain = class(TForm) 18 var 19 frmMain: TfrmMain; 20 implementation

Chapter 1, Page 24

Object orientation with Delphi (all rights reserved)

21 uses AuxForm; 22 {$R *.dfm} 23 procedure TfrmMain.radAuxShowClick(Sender: TObject); 24 begin 25 try 26 frmAuxiliary.Show; 27 except 28 ShowMessage ('Auxiliary Form does not exist'); 29 radAuxShow.Checked := False; 30 end; 31 end; // end procedure TfrmMain.radAuxShowClick 32 procedure TfrmMain.radAuxHideClick(Sender: TObject); 33 begin 34 try 35 frmAuxiliary.Hide; 36 except 37 ShowMessage ('Auxiliary Form does not exist'); 38 radAuxHide.Checked := False; 39 end; 40 end; // end procedure TfrmMain.radAuxHideClick 41 procedure TfrmMain.btnCreateClick(Sender: TObject); 42 begin 43 if frmAuxiliary = nil then 44 frmAuxiliary := TfrmAuxiliary.Create(Self) 45 else 46 ShowMessage ('Auxiliary Form already exists'); 47 end; // end procedure TfrmMain.btnCreateClick 48 procedure TfrmMain.btnFreeClick(Sender: TObject); 49 begin 50 try 51 frmAuxiliary.Hide; 52 frmAuxiliary.Free; 53 frmAuxiliary := nil; 54 except 55 ShowMessage ('Auxiliary Form does not exist'); 56 end; 57 end; // end procedure TfrmMain.btnFreeClick 58 end.

// end unit MainForm

The changes required may be more extensive than expected. Since at any particular moment frmAuxiliary may or may not exist, at each stage we need to test for frmAuxiliarys existence before trying to carry out any operations on it. (In the previous auto-create version we know that frmAuxiliary always exists and so we do not need these tests.) We have added an OnClick event handler for each of the two new buttons. Of the four event handlers we now have, three use exception handling to handle situations where we might try to perform an operation on a non-existent object.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 25

If we try to show a non-existent frmAuxiliary, line 26 throws an exception that is then caught by lines 28 and 29. Similarly, if we try to hide a non-existent form, line 35 throws an exception that is caught by lines 37 and 38. If we try to free a non-existent form (line 51) line 55 takes care of the required exception handling. Exception handling will not catch an attempt to create another frmAuxiliary should one already exist, so we use a different approach when instantiating frmAuxiliary. Line 43 tests whether the name frmAuxiliary refers to a valid object. If it doesnt, line 44 creates it. If it does, line 46 issues a message to the user and there is no attempt to instantiate a second TfrmAuxiliary object. Well use this example to look a little more closely at an objects life cycle and at the way it can be referenced by other objects. Line 21 is a local uses clause stating that this unit has access to the public sections of unit AuxForm. Unit Auxform declares a public variable (ie an object reference) frmAuxiliary of type TfrmAuxiliary (step 2, lines 10 & 11). Thus reference frmAuxiliary is visible to unit MainForm. If an object reference has the value nil it is not currently referring to any object: any other value is a reference to an object. When the user clicks btnCreate, its OnClick event handler runs. This first checks whether reference frmAuxiliary refers to a valid object (line 43 above). If not, it moves to line 44:
frmAuxiliary := TfrmAuxiliary.Create(Self)

This invokes TfrmAuxiliarys Create method, sending it the value Self. TfrmAuxiliary is declared publicly in unit AuxForm, and unit MainForm has access to AuxForm through its local uses clause (line 21 above). TfrmAuxiliary is derived from TForm (step 2 line 7). TForm has a method called Create, and so TfrmAuxiliary inherits Create from TForm: an example of how inheritance facilitates reuse. Create is a special kind of method called a Constructor. A Constructor creates an object from the template provided in a class definition. For VCL classes, this constructor requires an owner of the object as an input parameter. Here we give Self (ie frmMain) as the owner. The constructor returns a reference to the newly created object. In line 44 this return value is assigned to frmAuxiliary. Returning to the If statement in line 43, if frmAuxiliary refers to a valid object, line 46 issues a message stating that the object already exists and no attempt is made to create another instance of this object. Now that it exists, frmAuxiliary can be shown and hidden as often as required by the two RadioButton event handlers. When the time comes to destroy frmAuxiliary, line 51 first Hides it. If frmAuxiliary exists, this statement will be successful and line 52 will then invoke frmAuxiliarys Free method. Free is a Destructor type method that TfrmAuxiliary has inherited from TForm. After freeing frmAuxiliary, it no longer exists and so we must then set its reference to nil (line 53). After this, btnFrees OnClick event handler terminates. The other possibility is that Chapter 1, Page 26 Object orientation with Delphi (all rights reserved)

frmAuxiliary does not exist when line 51 executes. The attempt to refer to it then raises an exception and execution continues in the Except section of the Try Except End construct (ie at line 55). This issues a suitable message without any attempt to free the (nonexistent) object. Run and test this program. In the Delphi IDE a raised exception can optionally cause a break into the debugger at the point the exception is raised. To continue when this happens, press <F9> to resume running or <F7> or <F8> to single-step or step-over respectively. To enable or disable the break into the debugger on an exception, use Tools | Debugger Options in Delphi 6/7 or Tools | Options in Delphi 8. Instead of using exception handling, we could have coded the object freeing sequence in an If statement as follows:
procedure TfrmMain.btnFreeClick(Sender: TObject); begin if frmAuxiliary = nil then ShowMessage ('Auxiliary Form does not exist') else begin frmAuxiliary.Hide; frmAuxiliary.Free; frmAuxiliary := nil; end; end; // end procedure TfrmMain.btnFreeClick

In this variation we make sure frmAuxiliary actually does exist before we attempt an operation on it (ie to hide it). It is often possible to use either exception handling or If statements to prevent attempts at invalid object operations, and each approach has its advantages and disadvantages. In this module we generally use the exception handling approach. This gives a brief introduction to object Create and Free processes. We will return to these processes in more detail in a subsequent chapter.

Ex 1.3 step 8 Lifetimes in a sequence diagram


In step 7 we specifically create an object when we need it and free it afterwards when we are done with it, and so we are in complete control of its lifetime. We can show an objects lifetime explicitly in a sequence diagram (figure 16). The message to the objects Name represents the constructor and a cross over its lifeline shows its destruction.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 27

Ex 1.3 Summary: There are a number of stages to creating an object. First we create a class definition. A class is not yet an object and does not have its own data. We cannot use it directly since it is only a template. So we declare one or more names to act as object references and then instantiate the objects from the class definition. Although each object is built to the same template, the class definition, an instantiated object is an independent entity with a life of its own. For example, each form has its own position and caption, and we can reposition and resize each one independently without affecting the others. In UML, a class diagram shows the static structure of classes in the program. An object diagram provides a snapshot of the instantiated objects at a particular moment in the program. A sequence diagram shows dynamic behaviour between various objects. We have investigated issues around an objects lifetime, creating it and freeing it as needed instead of creating it when the program starts and freeing it when the program ends. We assumed responsibility for freeing the object by setting the owner to nil in the Create method call. When freeing an object we must also set its reference to nil. We do this either by calling the Free method and then setting the reference to nil, or (as well see in a future example) by using the FreeAndNil procedure. When needed, we can show the start and end of an objects lifeline on a sequence diagram. A message to the objects Name indicates its construction. A cross over its lifeline shows its destruction. There are several different kinds of message and we distinguish these through different notations.
Figure 16 Showing object creation and destruction on a sequence diagram

Chapter 1, Page 28

Object orientation with Delphi (all rights reserved)

Example 1.4 Defining a form directly in code


In the previous example, we used Delphis RAD facility to define the class TfrmAuxiliary. We then instantiated and freed it in program code. As an alternative, in this example we define TfrmAuxiliary directly from TForm using program code and then instantiate it.

Ex 1.4 step 1 Modifying the previous program


In a spirit of reuse, and to emphasise the changes well be making in this example, open the project from the previous example and then save it (ie the two units and the project file) to a new directory. Well modify this copy. Since well define the auxiliary form directly from TForm (line 48 below) we dont need unit AuxForm of the previous example. So in unit MainForm delete the local uses AuxForm statement. Now we need to remove AuxForm from the project. Use the menu sequence Project | Remove from Project, select unit AuxForm and click on OK. (To keep your directory tidy, you could now also delete unit AuxForm from the directory you are using for this example.) Unit AuxForm declared a reference to frmAuxiliary. This unit is no longer part of the project and so we declare this reference as a private data field in the type declaration of TfrmMain (lines 1718 below). The reference frmAuxiliary is now a private data field in TfrmMain. As in the previous example, if the object that frmAuxiliary refers to does not already exist (line 46) we create it, but this time we create it directly from the library class TForm (line 48). (In the previous example we created it from TfrmAuxiliary: example 1.3, step 4, line 44.) We now initialise it in program code (lines 4951) since we no longer have access to the Object Inspector to initialise frmAuxiliary. We also set the values of Left and Top for frmAuxiliary (lines 5253) since we dont have a suitable OnShow event handler (cf example 1.3, step 2, lines 1822). Showing, Hiding and Freeing frmAuxiliary remains the same process as before.
1 unit MainForm; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls; 6 type 7 TfrmMain = class(TForm) 8 radAuxShow: TRadioButton; 9 radAuxHide: TRadioButton; 10 gpbAuxiliary: TGroupBox;

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 29

11 12 13 14 15 16 17 18 19

btnCreate: TButton; btnFree: TButton; procedure radAuxShowClick(Sender: TObject); procedure radAuxHideClick(Sender: TObject); procedure btnCreateClick(Sender: TObject); procedure btnFreeClick(Sender: TObject); private frmAuxiliary: TForm; // Composition end; // end TfrmMain = class(TForm)

20 var 21 frmMain: TfrmMain; 22 implementation 23 {$R *.dfm} 24 procedure TfrmMain.radAuxShowClick(Sender: TObject); 25 begin 26 try 27 frmAuxiliary.Show; 28 except 29 ShowMessage ('Auxiliary Form does not exist'); 30 radAuxShow.Checked := False; 31 radAuxHide.Checked := False; 32 end; 33 end; // end procedure TfrmMain.radAuxShowClick 34 procedure TfrmMain.radAuxHideClick(Sender: TObject); 35 begin 36 try 37 frmAuxiliary.Hide; 38 except 39 ShowMessage ('Auxiliary Form does not exist'); 40 radAuxHide.Checked := False; 41 radAuxShow.Checked := False; 42 end; 43 end; // end procedure TfrmMain.radAuxHideClick 44 procedure TfrmMain.btnCreateClick(Sender: TObject); 45 begin 46 if frmAuxiliary = nil then 47 begin 48 frmAuxiliary := TForm.Create(Self); 49 frmAuxiliary.Caption := 'frmAuxiliary'; 50 frmAuxiliary.Height := 150; 51 frmAuxiliary.Width := 180; 52 frmAuxiliary.Left := Random (600); // not part of OnShow 53 frmAuxiliary.Top := Random (400); 54 end 55 else 56 ShowMessage ('Auxiliary Form already exists'); 57 end; // end procedure TfrmMain.btnCreateClick

Chapter 1, Page 30

Object orientation with Delphi (all rights reserved)

58 procedure TfrmMain.btnFreeClick(Sender: TObject); 59 begin 60 try 61 frmAuxiliary.Hide; 62 frmAuxiliary.Free; 63 frmAuxiliary := nil; 64 except 65 ShowMessage ('Auxiliary Form does not exist'); 66 end; 67 end; // end procedure TfrmMain.btnFreeClick 68 initialization 69 Randomize; 70 end.

// end unit MainForm

When you run this program it appears on the screen much as the previous examples. So what is the significance of the changes we have made? We declare frmAuxiliary (of class TForm) as a constituent of class TfrmMain by declaring it as a private data member (or data field) (line 18). We then create it (line 48), manipulate it (lines 4953) and, when we have finished with it, we free it (line 62). This private create-usefree relationship between one object and another is an example of composition. Its similar to association, but where association is a relationship between two independent objects, with composition one object creates, uses and destroys a private subsidiary object. Composition is an important concept in OO and well return to it several times in the chapters that follow.

Ex 1.4 step 2 Methods, and event handler linking


In step 1 above we see that when we create a form dynamically in code we have access to all of its (public) properties. But what about its events? Can we create and access those too? We can, as the following code shows. In the previous example we used the auxiliary forms OnShow event handler to assign random values to the Left and Top properties so that the subforms appear at different positions each time they are shown. Well change the program in the previous step to have a similar OnShow event handler. How do we set about creating an event handler? Lets see how Delphi sets about it and then attempt something similar. Whenever Delphi creates an event handler, it declares this event handler in the class definition (eg ex 1.3 step 2, line 8). In line 19 below we copy this format. The private and public sections of the class definition are for the programmers use and we place the event handler declaration in the private section (line 11) since this is the only unit that needs to access it. We can give the event handler any name we choose, and here well call it frmAuxiliaryShow.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 31

In RAD development, the link between an event and its handler is controlled through the Object Inspector. We cant use that here so we link the OnClick event to the frmAuxShow event handler in program code (eg line 53). Just as Width is a property to which we can assign either a constant or variable name (eg line 24), OnShow is a property to which we can assign the name of a suitable method. (Just as we must use appropriate types when assigning variables and not, for example, assign a string to an integer, when assigning methods they must have a matching method signature. That is why we define frmAuxShow with a Sender parameter of type TObject even though it is not used in the method (line 19).) Finally we implement the body of the event handler as we did previously (ex 1.3 step 2, lines 1822). It will run when the auxiliary form is shown on the screen because of the assignment in line 25. In summary, we have a private method (line 19 below) that is used as an event handler, ie initiated by an event, and so it follows same format as Delphi-generated event handlers. Since an events name (eg OnShow) is a property, we can link the event handler to the event for the object we create (eg line 53) This achieves the same effect as linking an event handler through the Object Inspector. The additional methods we create for the subsidiary form need not just be event handlers. They can also be helper or access methods that we can call through program code. Well create a helper method FormRefFail to use whenever we attempt an invalid reference to frmAuxiliary. First, we declare the method privately (line 20) since no other unit should have access to it. It is a procedure since we are not returning a value. (We look at access methods in subsequent examples.) Run this program. From an external, black-box perspective it works as before.
1 unit MainForm; 2 interface 3 uses 4 Windows, Messages, SysUtils, Variants, Classes, Graphics, 5 Controls, Forms, Dialogs, StdCtrls; 6 type 7 TfrmMain = class(TForm) 8 radAuxShow: TRadioButton; 9 radAuxHide: TRadioButton; 10 gpbAuxiliary: TGroupBox; 11 btnCreate: TButton; 12 btnFree: TButton; 13 procedure radAuxShowClick(Sender: TObject); 14 procedure radAuxHideClick(Sender: TObject); 15 procedure btnCreateClick(Sender: TObject); 16 procedure btnFreeClick(Sender: TObject);

Chapter 1, Page 32

Object orientation with Delphi (all rights reserved)

17 18 19 20 21

private frmAuxiliary: TForm; // Link: composition procedure frmAuxiliaryShow(Sender: TObject); // event handler procedure FormRefFail; // helper method end; // end TfrmMain = class(TForm)

22 var 23 frmMain: TfrmMain; 24 implementation 25 {$R *.dfm} 26 const // unit level constant 27 Mssgs: Array [0..1] of string = ('Auxiliary Form does not exist', 28 'Auxiliary Form already exists'); 29 procedure TfrmMain.radAuxShowClick(Sender: TObject); 30 begin 31 try 32 frmAuxiliary.Show; 33 except 34 FormRefFail; 35 end; 36 end; // end procedure TfrmMain.radAuxShowClick 37 procedure TfrmMain.radAuxHideClick(Sender: TObject); 38 begin 39 try 40 frmAuxiliary.Hide; 41 except 42 FormRefFail; 43 end; 44 end; // end procedure TfrmMain.radAuxHideClick 45 procedure TfrmMain.btnCreateClick(Sender: TObject); 46 begin 47 if frmAuxiliary = nil then 48 begin // setting frmAuxiliarys properties 49 frmAuxiliary := TForm.Create(Self); 50 frmAuxiliary.Caption := 'frmAuxiliary'; 51 frmAuxiliary.Height := 150; 52 frmAuxiliary.Width := 180; 53 frmAuxiliary.OnShow := frmAuxiliaryShow; // ref to event handler 54 end 55 else 56 ShowMessage (Mssgs [1]); 57 end; // end procedure TfrmMain.btnCreateClick 58 procedure TfrmMain.btnFreeClick(Sender: TObject); 59 begin 60 try 61 frmAuxiliary.Hide; 62 frmAuxiliary.Free; 63 frmAuxiliary := nil;

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 33

64 except 65 FormRefFail; 66 end; 67 end;

// end procedure TfrmMain.btnFreeClick

68 procedure TfrmMain.frmAuxiliaryShow(Sender: TObject); 69 begin 70 frmAuxiliary.Left := Random (600); 71 frmAuxiliary.Top := Random (400); 72 end; // end procedure TfrmAuxiliary.FormShow 73 procedure TfrmMain.FormRefFail; 74 begin 75 ShowMessage (Mssgs [0]); 76 radAuxHide.Checked := False; 77 radAuxShow.Checked := False; 78 end; // end procedure TfrmMain.FormRefFail 79 initialization 80 Randomize; 81 end.

// end unit MainForm

Ex 1.4 step 3 Matching UML diagrams


How can we represent the situation above in a class diagram? Two kinds of relationship exist between TfrmMain and TForm. First, TfrmMain is derived from TForm (line 7). Second, there is a composition relationship between the two since TfrmMain contains a private object of type TForm (line 18) that it defines, creates, uses and destroys. We can show both these connections between TfrmMain and TForm in the class diagram (figure 17). (Remember that inheritance is shown by a closed but unfilled arrowhead and composition by a filled diamond next to the composed class.)
Figure 17 A subclass containing an instance of its superclass

Notice that this diagram shows a relationship between classes, and not objects. It shows two relationships between the classes: we have derived a class, TfrmMain, from TForm and Chapter 1, Page 34 Object orientation with Delphi (all rights reserved)

TfrmMain carries, as a private data field, a reference to a (separate) object of type Tform. We dont show this reference in the diagram because it is implied by the solid diamond symbol and the link to Tform. Both the event handler linked by the programmer and the helper method are private, so their names are preceded by a minus symbol. All other operations (and attributes) so far have been public and so they have been preceded by a plus symbol. What about an object diagram? After clicking btnCreate on the main form, the object diagram is (figure 18):
Figure 18 Object diagram after clicking btnCreate

After clicking btnFree on the main form, the object diagram is (figure 19):
Figure 19 Object diagram after clicking btnFree

The sequence diagram for this version of the program remains the same as the previous one (figure 16).

Chapter Summary
In this chapter we have briefly seen: Delphis unit and project structure, RAD generation of visual objects in Delphi, the process of defining a class, declaring a reference to an object of that class, instantiating an object of that class, using the class and finally freeing that class and how to perform this in program code; the Inheritance (IsA), Association (UsesA) and Composition (UsesA) OO relationships; interaction between objects: simple message passing, association and composition, and UML graphical representations: a class diagram shows static inheritance and association structures, an object diagram snapshots objects and their relationships at a particular moment in the execution, and a sequence diagram shows sequential message passing between objects. This chapter has also introduced: Object orientation basics and Event handlers

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 35

Main points: 1. Understanding RAD generated code: classes and objects. 2. Generating visual objects through program code as a precursor to non-visual objects. 3. Inheritance, association and composition. 4. UML class, object and sequence diagrams. Objects as independent entities: Defining and using a class. Objects as derived entities: Simple inheritance and composition. Objects as interacting entities: Association and simple message passing. UML diagrams: Class diagram, object diagram and sequence diagram.

Problems
Problem 1.1 Study Chapter 1
Identify the appropriate example(s) or section(s) of the chapter to illustrate each comment made in the summary above.

Problem 1.2 Replace exception handling with If statements


Replace all the exception handling statements in example 1.3 step 7 with If statements.

Problem 1.3 Changed interface


The user interface given for example 1.3 step 7 mixes buttons and RadioButtons, leading to a confused user interface and to repetitive coding. Recode this program, replacing the various buttons with a single RadioGroup (figure 20 and figure 21). Use exception handling rather than If statements to
Figure 20 An improved user interface for demonstrating object creation, use and destruction

respond to object reference errors.

Chapter 1, Page 36

Object orientation with Delphi (all rights reserved)

Figure 21 Components comprising the user interface

Problem 1.4 Auto-create and program controlled create and free


In example 1.3 step 7 we remove frmAuxiliary from the auto-create list and then create and free it under program control. What happens if we leave frmAuxiliary in the auto-create list but still use the revised program given in example 1.3 step 7?

Problem 1.5 Creating objects explicitly


If you have coded problem 1.4 successfully, use it as a starting point for this problem. Modify it to define the auxiliary form in code similarly to example 1.4. If you have not coded problem 1.4 successfully, use example 1.4 as a starting point. 1. On the auxiliary form define two buttons, btnBlue and btnGreen, in code (ie not using RAD facilities). Give each an OnClick event handler to change the colour of the auxiliary form between MoneyGreen and SkyBlue. 2. Draw the matching UML diagrams, showing composition explicitly.

Introduction to OO basics (31 May 2006, all rights reserved)

Chapter 1, Page 37

Vous aimerez peut-être aussi