Reputation: 9294
I don't know OWNER object class name. So I must check everywhere in my codes like that :
if TObject(OWNER) is TFirstClass then begin
TFirstClass(OWNER).FirstFunction;
TFirstClass(OWNER).SecondFunction;
...
end else
if TObject(OWNER) is TSecondClass then begin
TSecondClass(OWNER).FirstFunction;
TSecondClass(OWNER).SecondFunction;
...
end;
Is there a better way? Because I must do this if condition in many place of the codes. All functions of TFirstClass and TSecondClass (which I have to run) are the same.
Note : I use Delphi 5.
Upvotes: 4
Views: 1336
Reputation: 6848
At first excuse-me for my bad english.
If you can't do the 2 before responses (Adapters and derive from a base class), you can use RTTI to access a procedure by it's name.
The procedure must be declared in the published section.
If you've a declaration like this:
TFirstClass = class(TObject)
published
procedure FirstFunction;
procedure SecondFunction;
end;
TSecondClass = class(TObject)
published
procedure FirstFunction;
procedure SecondFunction;
end
You can do something like this to execute a method if you have the name:
// Acceso a la rutina; TObject is a Base class for
// TFirstClass and TSecondClass
Routine.Data := Pointer(obj as TObject);
// Devuelve la dirección de un método published; Method for it's name
Routine.Code := (obj as TObject).MethodAddress('SecondFunction');
// Not find
if (Routine.Code = nil) then Exit;
// execute
TExecuteMethod(Routine);
You can see similar codes here:
* Tip4
* Tip7
Regards.
Upvotes: -1
Reputation: 32334
If you have no access to TFirstClass and TSecondClass, but still want to simplify your code, here's a way:
Create an adapter base class:
type
TMyAdapter = class(TObject)
public
procedure FirstMethod; virtual; abstract;
procedure SecondMethod; virtual; abstract;
end;
Then create descendant classes TFirstClassAdapter and TSecondClassAdapter and give them each a private reference to the instance of TFirstClass or TSecondClass respectively. Add a constructor which sets this reference. Override the methods of the adapter classes, so that they call through to the adapted classes.
type
TFirstClassAdapter = class(TMyAdapter)
private
fObject: TFirstClass;
public
constructor Create(AAdaptedObject: TFirstClass);
procedure FirstMethod; override;
procedure SecondMethod; override;
end;
constructor TFirstClassAdapter.Create(AAdaptedObject: TFirstClass);
begin
inherited Create;
fObject := AAdaptedObject;
end;
procedure TFirstClassAdapter.FirstMethod;
begin
fObject.FirstMethod;
end;
procedure TFirstClassAdapter.SecondMethod;
begin
fObject.SecondMethod;
end;
Same for the other class. Now you only need to decide whether you create the adapter once and pass it around, or whether you make a function that you call everywhere you need it, and which will give you an adapter for your concrete class.
If you implement the adapter using interfaces, then you will not even need to manage the lifetime of the adapter yourself.
This way you can have the polymorphic behaviour that Ulrich gave in his answer, but without the need to change TFirstClass and TSecondClass.
Upvotes: 12
Reputation: 14001
Derive TFirstClass and TSecondClass from a common base class that declares virtual methods FirstFunction and SecondFunction.
Uli.
Upvotes: 11