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.
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.
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.
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.
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.
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.
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.
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.
The idea that all activity in an application is comprised of objects sending and receiving message to and from other objects.
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.
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.
In order to define classes in code we need to use some new commands, let’s look at them.
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
ENDPROCENDDEF
How do we now create an object based on our class?
Creates an object from a class definition. Using the class MyClass above, we can create an object with this code;
oMyObject = CREATEOBJ( "MyClass" )
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 commandbuttonCREATE 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.
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, oThisFormcHairColor = "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.
ENDPROCPROTECTED 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)
ENDIFENDFOR
THIS.oThisForm.Mouth.Height = 2
ENDPROCPROCEDURE Hello
* respond to the outside world
lPARAMETERS pcMessage,pnTalk, pcMyNameIF 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
ENDPROCPROCEDURE GoodBye
* Release the form
THIS.oThisForm.Release()
* Release the objectRELEASE THIS
ENDPROCPROCEDURE Converse
* Converse with another object
Lparameters pcWho,pcMyNameIF TYPE( pcWho ) <> "O"
THIS.oThisForm.Label1.Caption = pcWho + ;
" is not available to talk to me."
RETURN
ENDIF
PRIVATE lnCntFOR 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
ENDCASETHIS.oThisForm.Label1.Caption = ""
THIS.Talk()
THIS.oThisForm.Label1.Caption = cMsg
cRequest = pcWho + '.Hello(cMsg ,2, pcWho)'
cRequest = &cRequestENDFOR
ENDPROC
PROCEDURE Contacts
* Change eye color
lPARAMETERS pcColorDO 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."
ENDCASEENDPROC
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
ENDPROCPROCEDURE Measure
* Change height
lPARAMETERS pcHeightIF pcHeight < THIS.cHeight
THIS.oThisForm.Face.Height = ;
THIS.oThisForm.Face.Height - 10ELSE
THIS.oThisForm.Face.Height = ;
THIS.oThisForm.Face.Height + 10
ENDIFTHIS.cHeight = pcHeight
ENDPROCENDDEFINE
DEFINE CLASS Employee AS PERSON
* Subclass of person
PROTECTED nSalarynSalary = 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.
ENDWITHPROCEDURE Raise
lPARAMETERS pnSalaryTHIS.nSalary = pnSalary
ENDPROC
PROCEDURE GetSalary
RETURN THIS.nSalary
ENDPROCPROCEDURE Hello
lPARAMETERS pcMessage,pnTalk, pcMyNameIF 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 formTop = 0
Left = 0
Height = 252
Width = 172
DoCreate = .T.
Name = "baseform"
BackColor = RGB(192,192,192)PROCEDURE Init
lPARAMETERS pNameTHISFORM.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 = ""
ENDWITHENDPROC
ENDDEFINE