Ivan Prodanov
Ivan Prodanov

Reputation: 35522

How to make this OO?

Sorry for the poor title,I'm new to OOP so I don't know what is the term for what I need to do.

I have, say, 10 different Objects that inherit one Object.They have different amount and type of class members,but all of them have one property in common - Visible.

type TSObject=class(TObject);
  protected
    Visible:boolean;
  end;

type
  TObj1=class(TSObject)
  private 
    a:integer;
    ...(More members)
end;
  TObj2=class(TSObject)
  private 
    b:String;
    ...(More members)
end;

...(Other 8 objects)

For each of them I have a variable.

var Obj1:TObj1;
    Obj2:TObj2;
    Obj3:TObj3;
    ....(Other 7 objects)

Rule 1: Only one object can be initialized at a time(others have to be freed) to be visible.

For this rule I have a global variable

var CurrentVisibleObj:TSObject; //Because they all inherit TSObject

Finally there is a procedure that changes visibility.

procedure ChangeObjVisibility(newObj:TSObject);
begin
  CurrentVisibleObj.Free; //Free the old object
  CurrentVisibleObj:=newObj; //assign the new object
  CurrentVisibleObj:= ??? //Create new object
  CurrentVisibleObj.Visible:=true; //Set visibility to new object
end;

There is my problem,I don't know how to initialize it,because the derived class is unknown(TObj1,TObj2,Tobj3...Which one?).

How do I do this?

I simplified the explanation,in the project there are TFrames each having different controls and I have to set visible/not visible the same way(By leaving only one frame initialized).

Sorry again for the title,I'm very new to OOP.

Upvotes: 1

Views: 420

Answers (5)

Ken Bourassa
Ken Bourassa

Reputation: 6467

One of the first problem here is that you seem to assume you can pass an uninitialized variable to ChangeObjVisibility.

ChangeObjVisibility(Obj3);

Here, if Obj3 is nil(or worse, a dangling pointer), ChangeObjVisibility has no way to know what is the type of the object it needs to create.

One of the way you could get the class of frame to create is with an array of const, or a function with a case.

type
  TSObjectClass = class of TSObject;
const
  ObjectClasses = array[0..X] of TSObjectClass = (TObj1, TObj2, TObj3, ...)

function GetFrameclass(Index : Integer) : TSObjectClass;
begin
  Result := ObjectClasses[Index]

  OR 

  case Index of
    0 : Result := TObj1;
    1 : Result := TObj2;
    (...)
  end;
end;

That will work if the frame doesn't need any kind of special initialization.

Next, you could have a call like this one :

procedure ChangeCurrentFrame(NewFrameIndex : Integer);
var FrameClass : TSObjectclass;
    vFrame : TSObject;
begin
  FrameClass := GetFrameClass(NewFrameIndex);
  if CurrentVisibleObj.ClassType <> FrameClass then
  begin
    vFrame := FrameClass.Create(nil);
    SetCurrentFrame(vFrame);
  end;
end;

procedure SetCurrentFrame(newObj:TSObject); 
begin 
  if Assigned(CurrentVisibleObj) then
    CurrentVisibleObj.Free; //Free the old object 
  CurrentVisibleObj:=newObj; //assign the new object 
  if Assigned(CurrentVisibleObj) then
    CurrentVisibleObj.Visible:=true; //Set visibility to new object 
end; 

Here, SetCurrentFrame replace you ChangeObjVisibility(What you really do here is change the current frame, changing the visibility is just a "side effect")

Upvotes: 1

marc_s
marc_s

Reputation: 754538

There is my problem,I don't know how to initialize it,because the derived class is unknown(TObj1,TObj2,Tobj3...Which one?).

Well, there are basically two options:

  • either you pass in the type of the object to be created as a parameter to your method, e.g. the caller has to tell you what it wants to be created

  • you can determine what type to create from some other information; one easy way would be to create an object of the same type as the one you originally passed in (don't know if that makes sense in your context)

It's been a while since I've done any serious Delphi work, but I think I vaguely remember there is a way in Delphi to express a "type" that you want to have. Or maybe you're even able to create an instance of a given type based on the name of the type as a string (e.g. create an instance of TObj2 based on the string "TObj2" being passed in)

Upvotes: 1

Mason Wheeler
Mason Wheeler

Reputation: 84550

If this is about a group of TFrame controls, and you want only one of them to be visible at a time, you don't need to go freeing and creating them all the time. You could just put each frame on one page of a TPageControl, then hide the tab strip and change the visible frame using the TPageControl's ActivePage property.

Upvotes: 1

David
David

Reputation: 7153

You shouldn't be creating and freeing your frames every time you want to change their visibility - they should all always be initialized all the time.

Upvotes: 0

Curtis White
Curtis White

Reputation: 6353

You can access a base property even on a derived object because of is-a relationship. In your case, you want to have a shared state among several objects, one way to think about this is to create a manager class which will hold the objects. It will only have one object selected as the visible object. You may not need the visible property on the contained objects but this design also permits that.

Container

List MyObjects; Object MyVisibleObject;

Upvotes: 0

Related Questions