delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback



Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi








Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (6)


Coding Tip..(pay it forward)Go to Derrick  Nel's websiteFormat this article printer-friendly!Bookmark function is only available for registered users!
Neat dynamic object creation
Product:
Delphi all versions
Category:
Object Pascal
Skill Level:
Scoring:
Last Update:
01/14/2002
Search Keys:
delphi delphi3000 article borland vcl code-snippet "code tip" "dynamic create" "pattern"
Times Scored:
8
Visits:
3125
Uploader: Derrick Nel
Company: Old Mutual plc
Reference: N/A
 
Question/Problem/Abstract:
How do handle dynamic object creation in a neat and effective way ?
Answer:



When one creates objects dynamically, as needed, your code inevitably becomes quite messy.  Checking to see if the object exists before creating it, eg.

if FMyVariable = nil then
  FMyVariable := TMyClass.Create;

Checking to see if the object exists before destroying it, e.g

if FMyVariable <> nil then
  FreeAndNil(FMyVariable)

Checking to see if the object exists before using it, e.g

if FMyVariable = nil then
begin
  FMyVariable := TMyClass.Create;
  FMyVariable.SomeMethod;
end;

OR

if FMyVariable <> nil then
  FMyVariable.SomeMethod;

Inevitably your code becomes scattered with code like the fragments shown above making maintenance a real difficult task.  If you needed to change the create you would have to hunt all over looking for the "if <> nil then create" or "if = nil then create",  with 4 simple methods you can neaten up your code and give maintenance programmers a break.

The four simple methods are :

procedure CreateObject;
procedure FreeObject;
function ObjectAllocated: Boolean;
procedure ObjectNeeded;

and this is how the code for each method looks;

procedure CreateObject;
begin
  FObject := TObject.Create;
end;

procedure FreeObject;
begin
  if ObjectAllocated then
    FreeAndNil(FObject);
end;

function ObjectAllocated: Boolean;
begin
  Result := (FObject <> nil);
end;

procedure ObjectNeeded;
begin
  if not ObjectAllocated then
    CreateObject;
end;

And that’s it, so instead of using :

"If FObject <> nil then" you use "if ObjectAllocated then", when you need the object simply call ObjectNeeded, and to destroy the object simply call FreeObject.  All the nitty-gritty if existance checking is already taken care of.  Here is a simple demo program that uses this technique:

DEMO APP:

Main Form in Text::
object Form1: TForm1
  Left = 371
  Top = 213
  Width = 236
  Height = 146
  Caption = 'Demo'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 8
    Top = 8
    Width = 100
    Height = 25
    Caption = 'Create Object'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 120
    Top = 8
    Width = 100
    Height = 25
    Caption = 'Free Object'
    TabOrder = 1
    OnClick = Button2Click
  end
  object Button3: TButton
    Left = 8
    Top = 44
    Width = 100
    Height = 25
    Caption = 'Show Classname'
    TabOrder = 2
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 120
    Top = 44
    Width = 100
    Height = 25
    Caption = 'Check Existance'
    TabOrder = 3
    OnClick = Button4Click
  end
  object Button5: TButton
    Left = 76
    Top = 84
    Width = 75
    Height = 25
    Caption = '&Close'
    Default = True
    TabOrder = 4
    OnClick = Button5Click
  end
end


Main form unit ::
unit FMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    procedure Button5Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FObject: TObject;
    procedure CreateObject;
    procedure FreeObject;
    function ObjectAllocated: Boolean;
    procedure ObjectNeeded;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

const
   ExistIdents: array[Boolean] of string =
     ('Object does not exist', 'Object Exists');

{ TForm1 }

procedure TForm1.CreateObject;
begin
  FObject := TObject.Create;
end;

procedure TForm1.FreeObject;
begin
  if ObjectAllocated then
    FreeAndNil(FObject);
end;

function TForm1.ObjectAllocated: Boolean;
begin
  Result := (FObject <> nil);
end;

procedure TForm1.ObjectNeeded;
begin
  if not ObjectAllocated then
    CreateObject;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ObjectNeeded;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FreeObject;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ObjectNeeded;
  ShowMessage(FObject.ClassName);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
//  if ObjectAllocated then
//    Showmessage('Object does not exist')
//  else
//    Showmessage('Object Exists');

  // this does exactly the same as above, but is also a preferred technique
  ShowMessage(ExistIdents[ObjectAllocated]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeObject;
end;

end.

Good luck,

Derrick....(dnel@oldmutual.com)

"programming in VB is like kicking a dead whale down a beach !!".






Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment
Some comments
    Dmitri Papichev (Jan 14 2002 4:25PM)

First, about your "messy" samples. Everywhere instead of "if ... = nil" you should rather use Assigned function, like this:

if NOT Assigned (FMyVariable) then begin
  FMyVariable := TMyClass.Create;
end; {if}

Then, if you free an object, you don't need to check if it is NIL - Free calls the destructor only if the object reference is not NIL, so you write just FreeAndNil (FMyVariable), and that's it.

And, last but not least, I completely disagree with your statement that "Inevitably your code becomes scattered with code like the fragments shown above making maintenance a real difficult task."  

Are you really sure that your code like this:

   ObjectNeeded;
   ShowMessage(FObject.ClassName);

(with the need for a whole bunch of separate procedures Object2Needed, Object3Needed, by the way :-) is more readable and maintainable than just

if NOT Assigned (FObject) then begin
   FObject := TObject.Create;
end; {if}
ShowMessage (FObject.ClassName);

?

If yes, I think you are wrong. Your code sample is less maintainable if just for one reason - there is no apparent to the reader link between first and second line in your sample. The reduction in the number of lines (2 against 4) doesn't matter here at all, contrary to what many believe :-)

Respond

RE: Some comments
Mat Hobbs (Jan 14 2002 7:06PM)

Even better perhaps for lazily-instantiated objects is to reduce the code to just one easy-to-read line:

GetMyObject.DoMyMethod(...);

where GetMyObject is simply a property/method/procedure which returns fMyObject from its variable, creating if required.

Respond

RE: RE: Some comments
Dmitri Papichev (Jan 14 2002 7:26PM)

That could be useful in some situations. However, with that approach, it is not obvious how to set necessary object properties before calling its method (as it is inseparable from the constructor here).
Respond

RE: RE: RE: Some comments
Mat Hobbs (Jan 14 2002 7:44PM)

True, but the answer then is to add parameters to the GetMyObject call.  The advantage being to modularize the construction/initialization away from the multiple places in your code that may want to call methods on the object.

Respond

RE: RE: RE: RE: Some comments
anonymus (Jan 15 2002 2:03AM)

Yes, I agree simply putting FreeAndNil(FVariable) sholud be sufficient, and if Assigned(FVariable) probably is better than if FVariable = nil.

However the technique is used within Delphi itself, granted not for object instanciation, but for allocation of a windows handle, check out the source for Controls.pas, TWincontrol in particular.

The question was asked, if this is how one coded:
ObjectNeeded;
FObject.Classname;

its practically a carbon copy of code found in Controls.pas,

  HandleNeeded;
  Result := FHandle;

if it works for Team B why shouldn't it work for the rest of us ??

WRT the Object1, Object2 point, not all objects used within another object are lazily constructed, are large portion are created and freed within the method in which they are used, most others are created in the contructor and destroyed in the destructor.

Lazily constructed objects are not widely used, they are created only when needed (hence ObjectNeeded), used only if allocated (hence ObjectAlllocated).  An example, if you have an object which allows other objects to register/unregister for notification purposes (subject/observer pattern), you would not create the list object which contains the observers if it is not needed, if an object registers for notification then one would create the list if not already created.  Throughout the subject object one would need to check for the existance of the list (ie are there observers) a whole lot of if ObjectAllocated would most certainly be far more readable than if Assigned(FVariable).  The methods in this example could more apprioately be named, i.e.

ListAllocated, ListNeeded, CreateList, FreeList.......

The demo application just shows that the code works....  Nothing more, dont read to much into it B-)

Respond

RE: RE: RE: RE: RE: Some comments
Mat Hobbs (Jan 15 2002 9:28AM)

Yes, its true we can easily make a mountain out of a molehill.

But I disagree that lazily-instantiated objects are rare.  In fact perhaps they should be universal.  Particularly in the era of distributed objects.  They are rare in practice only because programs are lazily-written!

A method containing logic to construct a used object which has external-to-the-method scope breaks principals of modularity (even if it is just a one-liner: "if fObject = nil then fObject := ...").  The GetMyObject() idea addresses this problem.

If it is a genuinely lazily-instantiated object then its construction code is well defined and should be put in its own method in one place.  If not, then it is a different object and not shared.

Respond














 
Sign up to consume product discounts for Bronze memberships !

read more


   


  Community Ad of
E. Irigoyen
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)