Mega Code Archive

 
Categories / Delphi / OOP
 

ENUMERATED TYPES Part I

Title: ENUMERATED TYPES Part I Question: Why use enumerated types? Answer: I was inspired to write this by a discussion in a Java News Group about the fact that there are no enumerated types in Java. Delphi has simple and powerful enumerated types. Another question would be why use enumerated types, what is wrong with constants. Heres why: Const acOpen := 0; acClose := 1; function Perform(pAction : Integer) : Boolean; in calling the Perform method I can pass any integer thus: Perform(acOpen); -- works Perform(acClose); -- works Perform(2); -- works also and could have undetermined results. By using Enumerated types we can avoid this: Type TSomeAction = (taOpen, taClose); function Perform(pSomeAction : TSomeAction) : Boolean; now when calling the method I can only pass something of type TSomeAction: Perform(taOpen); Perform(taClose); Perform(2); -- compiler error So why use enumerated types: Type Safety Readability Maintenance Here is another example of using enumerated types: unit Travel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TDirection = (drNorth, drSouth, drEast, drWest); TDirectionChangeEvent = procedure(Sender : TObject) of object; TCompassError = class(Exception); TCompass = class protected fHeading : Double; property Heading : Double read fHeading write fHeading; public constructor Create (pHeading : Double = 0.0); reintroduce; virtual; end; TTraveller = class(TForm) Button1: TButton; lbHeading: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } fCompass : TCompass; fOnDirectionChange : TDirectionChangeEvent; procedure DoDirectionChange; protected procedure SetHeading (pDirection : TDirection); virtual; procedure DisplayHeading(Sender : TObject); public { Public declarations } property OnDirectionChange : TDirectionChangeEvent read fOnDirectionChange write fOnDirectionChange; end; var Traveller: TTraveller; implementation {$R *.DFM} constructor TCompass.Create (pHeading : Double); begin fHeading := pHeading; end;//Create procedure TTraveller.SetHeading (pDirection : TDirection); begin case pDirection of //can be used in case statements for readability and easy development drNorth : fCompass.Heading := 0.0; drSouth : fCompass.Heading := 180.0; drEast : fCompass.Heading := 90.0; drWest : fCompass.Heading := 270.0; end;//case DoDirectionChange; end;//SetHeading procedure TTraveller.DisplayHeading(Sender : TObject); begin lbHeading.Caption := FloatToStr(fCompass.Heading); end; procedure TTRaveller.DoDirectionChange; begin if Assigned(fOnDirectionChange) then fOnDirectionChange(Self); end;//DoDirectionChange procedure TTraveller.FormCreate(Sender: TObject); begin fCompass := TCompass.Create; Traveller.OnDirectionChange := DisplayHeading; DoDirectionChange; end; procedure TTraveller.Button1Click(Sender: TObject); begin // Just so we can change the direction Randomly SetHeading(TDirection(Round(Random(4)))); end; end. Another argument is its not object oriented ? Answer in part II I have beefed up the previous example, thanks! to Pieter Valentijn for his comments. Here it is: unit Travel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TDirection = (drNorth, drSouth, drEast, drWest); TDirectionChangeEvent = procedure(Sender : TObject) of object; TCompassError = class(Exception); TCompass = class protected fHeading : Double; (* array size is set using TDirection , thus if you add values to TDirection such as drNorthEast. The size of your array will change too. *) FAvailableHeadings : array [Low(TDirection) .. High(TDirection)] of Double; function GetAvailableHeadings (Index : TDirection) : Double; procedure SetAvailableHeadings (Index : TDirection ; Value : Double ); property Heading : Double read fHeading write fHeading; public constructor Create (pHeading : Double = 0.0); virtual; property AvailableHeadings [index : TDirection] : Double read GetAvailableHeadings write SetAvailableHeadings; end; TTraveller = class(TForm) Button1: TButton; lbHeading: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } fCompass : TCompass; fOnDirectionChange : TDirectionChangeEvent; procedure DoDirectionChange; protected procedure SetHeading (pDirection : TDirection); virtual; procedure ScanHorizon; procedure DisplayHeading(Sender : TObject); public { Public declarations } property OnDirectionChange : TDirectionChangeEvent read fOnDirectionChange write fOnDirectionChange; end; var Traveller: TTraveller; implementation {$R *.DFM} constructor TCompass.Create (pHeading : Double); var vDirection : TDirection; begin inherited Create; fHeading := pHeading; // Using ENUMs in for loop for better control for vDirection := Low(TDirection) to High(TDirection) do AvailableHeadings[vDirection] := (Ord(VDirection) * 90.0); end;//Create function TCompass.GetAvailableHeadings (Index : TDirection) : Double; begin if Index in [Low(FAvailableHeadings)..High(FAvailableHeadings)] then Result := FAvailableHeadings[TDirection(Index)] else raise Exception.Create('Index out of bounds'); end; procedure TCompass.SetAvailableHeadings (Index : TDirection ; Value : Double ); begin if Index in [Low(FAvailableHeadings)..High(FAvailableHeadings)] then FAvailableHeadings[Index] := Value else raise Exception.Create('Index out of bounds'); end;//SetAvailableHeadings procedure TTraveller.SetHeading (pDirection : TDirection); begin fCompass.Heading := fCompass.AvailableHeadings[pDirection]; (*case pDirection of drNorth : fCompass.Heading := fCompass.AvailableHeadings[drNorth]; drSouth : fCompass.Heading := fCompass.AvailableHeadings[drSouth]; drEast : fCompass.Heading := fCompass.AvailableHeadings[drEast]; drWest : fCompass.Heading := fCompass.AvailableHeadings[drWest]; end;//case *) DoDirectionChange; end;//SetHeading procedure TTraveller.ScanHorizon; var vDirectionToLook : TDirection; begin // Using ENUMs in for loop for better control for vDirectionToLook := Low(TDirection) to High(TDirection) do //Do something such as check terrain; end; procedure TTraveller.DisplayHeading(Sender : TObject); begin lbHeading.Caption := FloatToStr(fCompass.Heading); end; procedure TTRaveller.DoDirectionChange; begin if Assigned(fOnDirectionChange) then fOnDirectionChange(Self); end;//DoDirectionChange procedure TTraveller.FormCreate(Sender: TObject); begin fCompass := TCompass.Create; Traveller.OnDirectionChange := DisplayHeading; DoDirectionChange; end; procedure TTraveller.Button1Click(Sender: TObject); var vMax : Integer; begin (* Just so we can change the direction Randomly Random number between 0 and vMax := Ord(High(TDirection))+1; SetHeading(TDirection(Random(vMax))); end; end.