tags:

views:

313

answers:

3
+4  Q: 

Check class name

Hi all;

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.

+11  A: 

Derive TFirstClass and TSecondClass from a common base class that declares virtual methods FirstFunction and SecondFunction.

Uli.

Ulrich Gerhardt
+12  A: 

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.

mghie
+1 for proposing a pattern. Adapterpattern is a handy pattern to know.
Vegar
A: 

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.

Neftalí