Mega Code Archive

 
Categories / Delphi / OOP
 

ENUMERATED TYPES Part II

Title: ENUMERATED TYPES Part II Question: Second part to my enumerated types article Answer: This second part looks at using objects as apposed to enumerated types. Here is my example: I included the interface ICompass which is implemented by the TCompass class. TTraveller now uses the ICompass as apposed to TCompass. First Unit our Compass class and interface: unit cls_Compass; interface uses Windows, Messages, SysUtils, Classes; type EDirectionError = class(Exception) end; (* No Enumerated types *) TDirection = class protected fHeading : Double; public constructor Create(pHeading : Double); virtual; property Heading : Double read fHeading; end; (* Created Interface ICompass which will be used by the TTraveller Class instead of TCompass *) ICompass = interface ['{2D7EB6E1-0295-11D5-A9CC-00105AA43BF4}'] function GetHeading : Double; procedure SetHeading (pDirection : TDirection); property Heading : Double read GetHeading; end; TCompass = class(TInterfacedObject, ICompass) protected fCurrentDirection : TDirection; (* No enumerated type here to set array dimensions so made it a TList *) FAvailableDirections : TList; function GetHeading : Double; procedure RegisterDirection (pDirection : TDirection); property Heading : Double read GetHeading; public constructor Create; virtual; destructor Destory; procedure SetHeading (pDirection : TDirection); property AvailableDirections : TList read FAvailableDirections; end; var drNorth, drSouth, drEast, drWest : TDirection; implementation constructor TDirection.Create(pHeading : Double); begin inherited Create; if (pHeading 359.9999) then raise EDirectionError.Create('Heading is outwith bounds'); fHeading := pHeading; end; constructor TCompass.Create; begin inherited; (* Must create our Directions first *) try drNorth := TDirection.Create(0.0); drEast := TDirection.Create(90.0); drSouth := TDirection.Create(180.0); drWest := TDirection.Create(270.0); except on EDirectionError do Exit; end;//try fCurrentDirection := drNorth; fAvailableDirections := TList.Create; (* Add our Directions to available directions *) RegisterDirection(drNorth); RegisterDirection(drEast); RegisterDirection(drSouth); RegisterDirection(drWest); end;//Create destructor TCompass.Destory; begin with FAvailableDirections do while Count 0 do begin TDirection(Items[0]).Free; Delete(0); end;//while end; procedure TCompass.RegisterDirection (pDirection : TDirection); begin fAvailableDirections.Add(pDirection); end;//RegisterDirection function TCompass.GetHeading : Double; begin Result := TDirection(fCurrentDirection).Heading; end;//GetHeading procedure TCompass.SetHeading(pDirection : TDirection); begin if FAvailableDirections.Indexof(pDirection) = -1 then raise EDirectionError.Create('Direction Not avaiable with this compass') else fCurrentDirection := TDirection(FAvailableDirections.Items[FAvailableDirections.Indexof(pDirection)]); end;//SetHeading end. Our Traveller Form : unit Travel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, cls_Compass; type TDirectionChangeEvent = procedure(Sender : TObject) of object; TTraveller = class(TForm) btnChangeCompass: TButton; lbHeading: TLabel; procedure FormCreate(Sender: TObject); procedure btnChangeCompassClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private (* Modified so TTraveller uses the ICompass interface *) fCompass : ICompass; fOnDirectionChange : TDirectionChangeEvent; procedure DoDirectionChange; protected procedure SetCompassHeading (pDirection : TDirection); virtual; procedure DisplayHeading(Sender : TObject); public { Public declarations } property OnDirectionChange : TDirectionChangeEvent read fOnDirectionChange write fOnDirectionChange; end; var Traveller: TTraveller; implementation {$R *.DFM} procedure TTraveller.SetCompassHeading (pDirection : TDirection); begin fCompass.SetHeading(pDirection); 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 try fCompass := TCompass.Create; except on EDirectionError do begin ShowMessage('Compass not Created properly'); Exit; end; end;//try Traveller.OnDirectionChange := DisplayHeading; DoDirectionChange; end; procedure TTraveller.btnChangeCompassClick(Sender: TObject); var vDirection : TDirection; begin (* Just so we can change the direction Randomly Random number between 0 and *) case Random(4) of 0: vDirection := drNorth; 1: vDirection := drEast; 2: vDirection := drWest; 3: vDirection := drSouth; else vDirection := drNorth; end;//case try SetCompassHeading(vDirection); except on E : EDirectionError do ShowMessage(E.Message); end; end; procedure TTraveller.FormDestroy(Sender: TObject); begin (* Cleanup *) if Assigned(drNorth) then drNorth.Free; if Assigned(drEast) then drEast.Free; if Assigned(drSouth) then drSouth.Free; if Assigned(drWest) then drWest.Free; end; end. Advantages: The main advantage of using objects is that if I want to add more instance variables to TDirection I can it do when it's a class. I can use OO inheritance etc.. TNewDirection = class(TDirection) Disadvantages: Extra Coding to get similar functionality, must instanciate all object and destory them afterwards. If I add another direction such as drNothEast means more coding. I welcome any of your comments. (***************************************************************************) Here the code without the Global Vars: Compass Unit: unit cls_Compass; interface uses Windows, Messages, SysUtils, Classes; type EDirectionError = class(Exception) end; (* No Enumerated types *) TDirection = class protected fHeading : Double; fDirectionName : String; public constructor Create(pHeading : Double; pDirectionName : String ); virtual; property Heading : Double read fHeading; property DirectionName : String read fDirectionName; end; (* Created Interface ICompass which will be used by the TTraveller Class instead of TCompass *) ICompass = interface ['{2D7EB6E1-0295-11D5-A9CC-00105AA43BF4}'] function GetHeading : Double; function GetDirection(pDirectionName : String) : TDirection; procedure SetHeading (pDirection : TDirection); property Heading : Double read GetHeading; end; TCompass = class(TInterfacedObject, ICompass) protected fCurrentDirection : TDirection; (* No enumerated type here to set array dimensions so made it a TList *) FAvailableDirections : TList; function GetHeading : Double; property Heading : Double read GetHeading; public constructor Create; virtual; destructor Destory; procedure SetHeading (pDirection : TDirection); function GetDirection(pDirectionName : String) : TDirection; //function GetDirection(pHeading : Double) : TDirection; property AvailableDirections : TList read FAvailableDirections; end; implementation constructor TDirection.Create(pHeading : Double; pDirectionName : String); begin inherited Create; if (pHeading 359.9999) then raise EDirectionError.Create('Heading is outwith bounds'); fHeading := pHeading; fDirectionName := pDirectionName; end; constructor TCompass.Create; begin inherited; (* Must create our Directions first *) try fAvailableDirections := TList.Create; (* Add our Directions to available directions *) fAvailableDirections.Add(TDirection.Create(0.0,'North')); fAvailableDirections.Add(TDirection.Create(90.0,'East')); fAvailableDirections.Add(TDirection.Create(180.0,'South')); fAvailableDirections.Add(TDirection.Create(270.0,'West')); except on EDirectionError do Exit; end;//try fCurrentDirection := TDirection(fAvailableDirections.Items[0]); end;//Create destructor TCompass.Destory; begin with FAvailableDirections do while Count 0 do begin TDirection(Items[0]).Free; Delete(0); end;//while end; function TCompass.GetDirection(pDirectionName : String) : TDirection; var CurrentDirectionToCheck : Integer; begin CurrentDirectionToCheck := 0; Result := nil; with fAvailableDirections do while CurrentDirectionToCheck begin if TDirection(fAvailableDirections.Items[CurrentDirectionToCheck]).DirectionName = pDirectionName then begin Result := TDirection(fAvailableDirections.Items[CurrentDirectionToCheck]); Exit; end;//if Inc(CurrentDirectionToCheck); end;//while if Result = nil then Raise EDirectionError.Create('This Direction is not available with this compass'); end;//GetDirection function TCompass.GetHeading : Double; begin Result := TDirection(fCurrentDirection).Heading; end;//GetHeading procedure TCompass.SetHeading(pDirection : TDirection); begin if FAvailableDirections.Indexof(pDirection) = -1 then raise EDirectionError.Create('Direction Not avaiable with this compass') else fCurrentDirection := TDirection(FAvailableDirections.Items[FAvailableDirections.Indexof(pDirection)]); end;//SetHeading end. Traveller unit: unit Travel; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, cls_Compass; type TDirectionChangeEvent = procedure(Sender : TObject) of object; TTraveller = class(TForm) btnChangeCompass: TButton; lbHeading: TLabel; procedure FormCreate(Sender: TObject); procedure btnChangeCompassClick(Sender: TObject); private (* Modified so TTraveller uses the ICompass interface *) fCompass : ICompass; fOnDirectionChange : TDirectionChangeEvent; procedure DoDirectionChange; protected procedure SetCompassHeading (pDirection : TDirection); virtual; procedure DisplayHeading(Sender : TObject); public { Public declarations } property OnDirectionChange : TDirectionChangeEvent read fOnDirectionChange write fOnDirectionChange; end; var Traveller: TTraveller; implementation {$R *.DFM} procedure TTraveller.SetCompassHeading (pDirection : TDirection); begin fCompass.SetHeading(pDirection); 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 try fCompass := TCompass.Create; except on EDirectionError do begin ShowMessage('Compass not Created properly'); Exit; end; end;//try Traveller.OnDirectionChange := DisplayHeading; DoDirectionChange; end; procedure TTraveller.btnChangeCompassClick(Sender: TObject); var vDirection : TDirection; begin (* Just so we can change the direction Randomly Random number between 0 and *) try case Random(4) of 0: vDirection := fCompass.GetDirection('North'); 1: vDirection := fCompass.GetDirection('East'); 2: vDirection := fCompass.GetDirection('South'); 3: vDirection := fCompass.GetDirection('West'); end;//case SetCompassHeading(vDirection); except on E : EDirectionError do ShowMessage(E.Message); end;//try end; end.