Session E-IOOP

Introduction to Object-Oriented Programming

Jim Booth
James Booth Consulting


What is Object Orientation?

Object Orientation is an approach to the analysis and design of software systems which involves the identification of self-contained components which can be linked together to produce complete applications. These components achieve the encapsulation of data and function, the ability to inherit things from other components, and can communicate with each other by sending messages back and forth.

What is a Class, Object?

Object Oriented systems are created through the definition of Classes which are then used to create Objects. Edward Yourdan defines a class as:

"A collection of one or more Objects with a uniform set of Attributes and Services, including a description of how to create new Objects in the Class."

Grady Booch defines an Object as follows:

"An object has state, behavior, and identity; the structure and behavior of similar objects are defined in their common class; the terms instance and object are interchangeable"

The difference between a Class and an Object is in the fact that Classes are the definition from which Objects are created. Objects exist and can communicate with other objects, but Classes only exist as blueprints from which Objects are instantiated.

Let’s take the analogy of the blueprint a little further. If we decide that we want to build a house, we start by getting an architect to draw plans, or a blueprint, for your house. We cannot move into the blueprint, nor can we cook on the stove in the kitchen of the blueprint. The blueprint is the class definition for our house, it is not an object.

We would then retain a builder to build the house based on the blueprint. The blueprint tells where the kitchen will be, how high the ceilings will be, where the doors and windows will be, etc.. Once the builder finishes, we can move in to the house he built, we can cook on the stove in the kitchen of the house. We can do these things because the house is an object, a real thing that actually exists.

This same process exists in Object Oriented Development. We first define the classes, or blueprints, for our objects. We cannot run the application with only these classes, we must first create objects based on the classes. It is the objects that are actually real things in our application. Just as the blueprint for our house can be used to build another house just like ours, we can use our class definition to create other objects that have the same properties and methods. We can even create a new class definition that is based on another class defintition.

Qualities of Object Orientation

There are certain qualities that describe an Object Oriented design. Many of these qualities are also descriptive of other earlier design methods such as Modular or Structured, but none of the earlier design methodologies encompass all of these qualities.

Abstraction

This is the ability to present a complex problem in a simplified model. All programming methodologies include the ability to abstract the overall design in a simplified model, but OO takes this to the extreme.

In OO we are able to create a heirarchy of classes. At the top of that tree the class defintions are so abstract that we would never use them to create an object (in fact, these are called Abstract Classes). Let’s look at command buttons as an example. We recognize that we need a number of different command buttons in our application, Exit buttons, Edit buttons, Add buttons, Save buttons, and Cancel buttons among others. We begin to define these and realize that we want all of these buttons to have the same Font and dimensions. So we create a class called OurButtons and give that class the Font and size we want. We then create a class called ExitButton which is based on OurButtons. ExitButton has the font and size of OurButtons because it is a subclass. We add code to this class to release the form when it is clicked. We would continue to create other subclasses for the other buttons we need.

What we have done, in recognizing the class OurButtons, is abstract our class definitions.

Encapsulation

The ability to completely hide the details of the implementation of a object’s behavior within the object by providing a public interface to the object and precluding any access to the object's methods and properties other than through that public interface.

Inheritance

The ability of an object to take all or part of its definition from another object. In the buttons example above we have inherited the Font and Size for our ExitButton from the class OurButtons.

Polymorphism

The ability of an operation to apply to several objects. Polymorphism comes in two flavors, Inherent and Ad Hoc. Inherent polymorphism describes the ability of a single operation to be available to every subclass under a class hierarchical tree. Ad Hoc polymorphism describes the ability for differing operations to have the same name in different classes.

Say we create a class called Person and give that class a method called Print which prints the object on the printer. Then we create a subclass of Person called Customer. Customer will have a Print method also. This is Inherent Polymorphism - both person and customer have a Print method.

If we now create a class called Invoice and give it a method named Print that prints the invoice, we would have Customer Print and Invoice Print methods each having the same name but doing something different. This is Ad Hoc Polymorphism.

Specialization

The concept means that, as we walk down the tree of class definitions, we find that the classes become more and more specialized in their operations. For example we might see a class hierarchy for Command Buttons like this;

1 Command Button

1.1 Gray Command Button

1.1.1 Gray Exit Command Button

1.1.1.1 Gray Application Exit Command Button

At each level of this tree the class is more specific than at the level above it.

Object Communications

The idea that all activity in an application is comprised of objects sending and receiving message to and from other objects.

Reuse

The idea is of component reuse is not unique to Object Orientation. However, due to the other qualities of OO, reuse is considerably more achievable. Becasue we spend most of our development time in OO building Class Definitions which are then used to create objects and that these classes can be used over and over again. We can achieve a much higher level of reuse of our work.

OO and VFP

Visual FoxPro is an Object Oriented development environment. VFP gives us the ability to define our classes in code or to use the Visual Class Designer to produce Visual Class Library (VCX) files.

Let’s first look at using code.

Creating Classes in Code

In order to define classes in code we need to use some new commands, let’s look at them.

DEFINE CLASS

Allows creation of classes in program code. The DEFINE CLASS command is used to begin a class definition; the definition ends with the ENDDEFINE keyword. Between these two commands you can define properties (variables) and methods (procedures) for the class. The syntax of the DEFINE CLASS command is as follows;

DEFINE CLASS <Class name> AS <Parent class name>

Following this command line we can add properties and methods to the class. The example below shows a simple class definition.

DEFINE CLASS MyClass AS Custom

PROTECTED cName
cName = "MyClass"

PROCEDURE SetName
LPARAMETERS cNewName
THIS.cName = cNewName
ENDPROC

ENDDEF

Creating Objects in Code

How do we now create an object based on our class?

CreateObj()

Creates an object from a class definition. Using the class MyClass above, we can create an object with this code;

oMyObject = CREATEOBJ( "MyClass" )

Visual Classes (VCX)

VFP gives us the ability to use visual tools to do most of our work. Among these tools is the Visual Class Designer. This tool gives us a visual interface through which we can define classes to be used later to create objects. These class definitions are stored in a Visual Class Library file (VCX). The commands we use to create and work with these Visual Class Libraries are explained below.

CREATE CLASSLIB buttons.vcx
CREATE CLASS cmdButton OF Buttons.vcx AS commandbutton

CREATE CLASS cmdExit OF Buttons.vcx AS cmdbutton;
FROM Buttons.vcx

The first line in the code above creates a VCX file named Buttons.vcx. This is our class library. This command does not bring us into the Visual Class Designer though, because we haven’t, yet, started to create a class definition.

The second line creates a class named cmdButton in this class library that is a subclass of the base class (FoxPro built in class) CommandButton. This command results in our seeing the Visual Class Designer and being able to define the class’ properties and methods visually.

The third command shows how to create a new class in our library that is a subclass of another class in our library.

Putting it together (Person and Employee)

Defining the class

The following code example defines the classes Person and Employee. Person is a custom class and employee is a subclass of person. This code may look very different to you from other examples you have seen. That may be because this code is defining real things and not variations of buttons and textboxes.

We have heard that OO is supposed to make it easier to analyze a business’ problem and then create an application that will address that problem. I find it interesting that when I analyze a business problem I identify things like Invoices, Customers, Employees, Orders, etc.. Yet when I read about OOP I read about Command Buttons, Option Buttons, Text Boxes, and Forms. Somehow these two sets of things don’t map well to each other.

How do I create a class definition for a Customer? or for an Employee? The last time I looked Employee’s did not have any command buttons on them. That's true, our employee objects don’t have command buttons. They have salaries, birthdates, hiredates, etc. Employees don’t have Click methods either, neither do they have MouseOver, or double click methods. Employees have Raise, Hire, Fire, Edit, Create methods and so on.

We programmers have this desire to see everything as a form or a control. The real world doesn’t work that way and OO IS the bridge that allows us to better model the real world. In the real world we have a thing called an Employee, and that thing has the ability to display itself on a form. So when we build our model of the real world, we shouldn’t expect to see a form as anything but a contained property of some other class, some class that describes a real thing in the real world. This form is simply a tool that the class uses to display itself.

The program code for these classes is listed here. On the disk, you'll have a VCX Visual Class Library for these class definitions as well.

DEFINE CLASS Person AS Custom
* The person class definition

* Define the properties of the Person class
PROTECTED cHairColor, cEyeColor, cHeight, ;
cAnswer, cRequest, cName, oThisForm

cHairColor = "Auburn"
cEyeColor = "Blue"
cHeight = "6 foot 2"
cAnswer = ""
cName = "John"
oThisForm = 0

* Define the methods of the person class
PROCEDURE Init
lPARAMETERS pName

* Update the Name property
THIS.cName = pName
* Create the visible form
THIS.oThisForm = CreateObj( "PersonForm", THIS.cName )

* Put the shapes in the form
WITH THIS.oThisForm

.AddObject( "Face", "Shape")
.Face.BackColor = RGB(255,255,0)
.Face.Curvature = (90)
.Face.Height = 133
.Face.Left = 12
.Face.Top = 24
.Face.Width = 145
.Face.Name = "Face"
.Face.Visible = .T.

.AddObject( "Lefteye", "Shape" )
.LeftEye.BackColor = RGB(0,0,255)
.LeftEye.Height = 13
.LeftEye.Left = 108
.LeftEye.Top = 60
.LeftEye.Width = 13
.LeftEye.Name = "LeftEye"
.LeftEye.Visible = .T.

.AddObject( "Righteye", "Shape" )
.RightEye.BackColor = RGB(0,0,255)
.RightEye.Height = 13
.RightEye.Left = 48
.RightEye.Top = 60
.RightEye.Width = 13
.RightEye.Name = "RightEye"
.RightEye.Visible = .T.

.AddObject( "Hair", "Shape" )
.Hair.BackColor = RGB(128,0,0)
.Hair.Curvature = 40
.Hair.Height = 37
.Hair.Left = 12
.Hair.Top = 12
.Hair.Width = 145
.Hair.Name = "Hair"
.Hair.Visible = .T.

.AddObject( "Label1", "Label" )
.Label1.BackColor = RGB(255,255,128)
.Label1.Caption = ""
.Label1.ForeColor = RGB(0,0,128)
.Label1.Height = 49
.Label1.Left = 12
.Label1.Top = 180
.Label1.Width = 145
.Label1.Name = "Label1"
.Label1.WordWrap = .T.
.Label1.Visible = .T.

.AddObject("Mouth", "Shape")
.Mouth.BackColor = RGB(0,0,0)
.Mouth.Curvature = 90
.Mouth.Height = 2
.Mouth.Left = 72
.Mouth.Top = 120
.Mouth.Width = 25
.Mouth.Name = "Mouth"
.Mouth.Visible = .T.

.Name = THIS.cName
.Caption = THIS.cName
.Hair.BackColor = RGB(128,0,0)
.LeftEye.BackColor = RGB(0,0,128)
.RightEye.BackColor = RGB(0,0,128)

ENDWITH
THIS.oThisForm.Refresh()
THIS.oThisForm.Visible = .T.
ENDPROC

PROTECTED PROCEDURE Talk
* Make the mouth move. This is a protected method.

PRIVATE lnCnt

FOR lnCnt = 1 TO 20

IF MOD( lnCnt, 5 ) = 0
IF MOD( lnCnt,2 ) = 0
THIS.oThisForm.Mouth.Height = 25
ELSE
THIS.oThisForm.Mouth.Height = 2
ENDIF
THIS.oThisForm.Refresh()
=INKEY(.2)
ENDIF

ENDFOR
THIS.oThisForm.Mouth.Height = 2
ENDPROC

PROCEDURE Hello
* respond to the outside world
lPARAMETERS pcMessage,pnTalk, pcMyName

IF EMPTY(pcMessage)
pcMessage = " "
ENDIF
IF EMPTY(pnTalk)
pnTalk = 0
ENDIF

* Check the message to see how to repsond
DO CASE
CASE "HOW ARE YOU" $ UPPER(pcMessage)
cAnswer = "I am fine thank you."
CASE "HOW TALL" $ UPPER(pcMessage)
cAnswer = "I am " + THIS.cHeight
CASE "COLOR" $ UPPER(pcMessage) AND ;
"EYES" $ UPPER(pcMessage)
cAnswer = "My eyes are " + THIS.cEyeColor
CASE "COLOR" $ UPPER(pcMessage) AND ;
"HAIR" $ UPPER(pcMessage)
cAnswer = "My hair is " + THIS.cHairColor
CASE "HELLO" $ UPPER( pcMessage )
cAnswer = "Hello"
CASE "GOODBYE" $ UPPER( pcMessage )
cAnswer = "Goodbye"
OTHERWISE
cAnswer = "I don't understand."
ENDCASE
THIS.oThisForm.Label1.Caption = ""
THIS.Talk()
THIS.oThisForm.Label1.Caption = cAnswer
ENDPROC

PROCEDURE GoodBye
* Release the form
THIS.oThisForm.Release()
* Release the object

RELEASE THIS
ENDPROC

PROCEDURE Converse
* Converse with another object
Lparameters pcWho,pcMyName

IF TYPE( pcWho ) <> "O"
THIS.oThisForm.Label1.Caption = pcWho + ;
" is not available to talk to me."
RETURN
ENDIF
PRIVATE lnCnt

FOR lnCnt = 1 TO 7
DO CASE
CASE lnCnt = 1
cMsg = "Hello, " + SUBSTR(pcWho, 2)
CASE lnCnt = 2
cMsg = "How are you today?"
CASE lnCnt = 3
cMsg = "How tall are you, " + SUBSTR(pcWho, 2) +;
"?"
CASE lnCnt = 4
cMsg = "What color eyes do you have?"
CASE lnCnt = 5
cMsg = "And your hair is what color?"
CASE lnCnt = 6
cMsg = "Goodbye"
OTHERWISE
THIS.oThisForm.Label1.Caption = cMsg
RETURN
ENDCASE

THIS.oThisForm.Label1.Caption = ""
THIS.Talk()
THIS.oThisForm.Label1.Caption = cMsg
cRequest = pcWho + '.Hello(cMsg ,2, pcWho)'
cRequest = &cRequest

ENDFOR

ENDPROC

PROCEDURE Contacts
* Change eye color
lPARAMETERS pcColor

DO CASE
CASE UPPER(pcColor) = "BLUE"
THIS.cEyeColor = pcColor
THIS.oThisForm.RightEye.BackColor = RGB(0,0,255)
THIS.oThisForm.LeftEye.BackColor = RGB(0,0,255)
CASE UPPER(pcColor) = "BROWN"
THIS.cEyeColor = pcColor
THIS.oThisForm.RightEye.BackColor = RGB(128,128,0)
THIS.oThisForm.LeftEye.BackColor = RGB(128,128,0)
CASE UPPER(pcColor) = "GREEN"
THIS.cEyeColor = pcColor
THIS.oThisForm.RightEye.BackColor = RGB(0,255,0)
THIS.oThisForm.LeftEye.BackColor = RGB(0,255,0)
CASE UPPER(pcColor) = "BLACK"
THIS.cEyeColor = pcColor
THIS.oThisForm.RightEye.BackColor = RGB(0,0,0)
THIS.oThisForm.LeftEye.BackColor = RGB(0,0,0)
OTHERWISE
THIS.oThisForm.Label1.Caption = ;
"I don't have that color."
ENDCASE

ENDPROC

PROCEDURE DyeHair
* Change hair color
lPARAMETERS pcColor
DO CASE
CASE UPPER(pcColor) = "BLUE"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(0,0,255)
CASE UPPER(pcColor) = "BROWN"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(128,128,0)
CASE UPPER(pcColor) = "GREEN"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(0,255,0)
CASE UPPER(pcColor) = "BLACK"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(0,0,0)
CASE UPPER(pcColor) = "BLOND"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(255,255,0)
CASE UPPER(pcColor) = "PLATINUM"
THIS.cHairColor = pcColor
THIS.oThisForm.Hair.BackColor = RGB(255,255,255)
OTHERWISE
THIS.oThisForm.Label1.Caption = ;
"I don't have that color."
ENDCASE
ENDPROC

PROCEDURE Measure
* Change height
lPARAMETERS pcHeight

IF pcHeight < THIS.cHeight
THIS.oThisForm.Face.Height = ;
THIS.oThisForm.Face.Height - 10

ELSE
THIS.oThisForm.Face.Height = ;
THIS.oThisForm.Face.Height + 10
ENDIF

THIS.cHeight = pcHeight
ENDPROC

ENDDEFINE

DEFINE CLASS Employee AS PERSON
* Subclass of person
PROTECTED nSalary

nSalary = 25000

PROCEDURE Init
lPARAMETERS pName

* Call the Person Init
PERSON::Init(pName)

WITH THIS.OThisForm
.AddObject( "Label2", "Label" )
.Label2.BackColor = RGB(192,192,192)
.Label2.Caption = "$"
.Label2.ForeColor = RGB(255,0,0)
.Label2.Height = 15
.Label2.Left = 2
.Label2.Top = 2
.Label2.Width = 15
.Label2.Name = "Label2"
.Label2.Visible = .T.
ENDWITH

PROCEDURE Raise
lPARAMETERS pnSalary

THIS.nSalary = pnSalary

ENDPROC

PROCEDURE GetSalary
RETURN THIS.nSalary
ENDPROC

PROCEDURE Hello
lPARAMETERS pcMessage,pnTalk, pcMyName

IF EMPTY(pcMessage)
pcMessage = " "
ENDIF
IF EMPTY(pnTalk)
pnTalk = 0
ENDIF
IF "SALARY" $ UPPER( pcMessage )
cAnswer = "My salary is " + ;
TRANSFORM(THIS.nSalary,"$999,999")
THIS.oThisForm.Label1.Caption = cAnswer
RETURN cAnswer
ENDIF

* Call the Person Hello
PERSON::Hello(pcMessage,pnTalk,pcMyName)

ENDPROC

ENDDEFINE

DEFINE CLASS PersonForm AS Form
* The person form

Top = 0
Left = 0
Height = 252
Width = 172
DoCreate = .T.
Name = "baseform"
BackColor = RGB(192,192,192)

PROCEDURE Init
lPARAMETERS pName

THISFORM.Name = pName

ENDPROC

PROCEDURE Click

WITH THISFORM
.Top = .Top - 5
.Left = .Left - 5
.Width = .Width + 10
.Height = .Height + 10
.Mouth.Height = 25
.Label1.Caption = "Ohhhhh, that tickles!"
.Top = .Top + 5
.Left = .Left + 5
.Width = .Width - 10
.Height = .Height - 10
=INKEY(2)
.Mouth.Height = 2
.Label1.Caption = ""
ENDWITH

ENDPROC
ENDDEFINE