Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling methods of a class inherited form an interface and another ancestor

I have problem with implementing relation between some classes. I got three different classes serving three different forms. All these classes speak in same language, so they are inherited from same class called TAncestorServer. Let’s call its descendants TForm1Server, TForm2Server, and TForm3Server. TAncestorServer contains an abstract method called Function1, so TForm1, TForm2, and TForm3 can call it with no problem through their own classes inherited from it, they have an access to the classes through a property named Server. But the problem is about another form called TForm4! It’s very similar to other forms but it’s not independent like them. It works with TForm2Server or TForm3Server. Still not a problem, but imagine another method like Function2 which is declared in TForm2Server and TForm3Server, TForm4 needs to call them. I can go like this:

if Server is TForm2Server then
   TForm2Server(Server).Function2
else if Server is TForm3Server then
  TForm3Server(Server).Function2;

But it can turn in an infinite if-else clause! So I thought something like multiple-inheritance may help here. I declared an interface called IForm4Server which contains Function2. So TForm2Server and TForm3Server inherit from both TAncestorServer and IForm4Server. I thought something like this could work:

If Server is IForm4Server then
  IForm4Server(Server).Function2;

But compiler doesn’t think so, it says that it’s not a valid type cast, because TAncestorServer is not IForm4Server, which is absolutely right. TForm1Server has no idea about implementing Function2 and has to leave it blank. I can’t declare TForm4.Server as IForm4Server too, because Function1 represents a huge number of methods and properties, however I still can’t type cast IForm4Server to TAncestorServer.

As a solution I can define two different properties in TForm4 like GeneralServer: TAncestorServer and Form4Server: IForm4Server and then assign same instance of TForm2Server or TForm3Server to them, but I don’t feel good about it. How should I do this? Is there any standard pattern for it?

like image 813
saastn Avatar asked Feb 20 '13 22:02

saastn


People also ask

Can interface be inherited by another interface?

Interfaces can inherit from one or more interfaces. The derived interface inherits the members from its base interfaces. A class that implements a derived interface must implement all members in the derived interface, including all members of the derived interface's base interfaces.

When an interface inherits another interface the implementing class must?

When a class implements the inherited interface then it must provide the implementation of all the members that are defined within the interface inheritance chain.

Are interface methods inherited?

But unlike classes, interfaces can actually inherit from multiple interfaces. This is done by listing the names of all interfaces to inherit from, separated by comma. A class implementing an interface which inherits from multiple interfaces must implement all methods from the interface and its parent interfaces.

Which keyword is used to classes and interface are inherited?

The interface keyword is used to declare a special type of class that only contains abstract methods. To access the interface methods, the interface must be "implemented" (kinda like inherited) by another class with the implements keyword (instead of extends ).


1 Answers

Implementing one or many interfaces is the correct approach, but looks like you're a bit confused about the proper syntax and have no experience with interfaces.

Basic things are:

  • You have a common ancestor class (or form) for any number of classes. The ancestor declares virtual methods that the classes specialize in some way.
  • Declare a Interface with any number of methods. Don't forget to add a GUID to your interface.
  • Extend your form declarations to implement the declared Interface, adding the Interface to the class declaration and adding the declared methods.
  • You now can:
    • Polymorphically call any virtual method using the ancestor class
    • Ask any form if it implements a interface, and if it does, retrieve a interface reference to it and call any interface method. All this can be done using the supports function.

I made the most simple example I can think off, using visual inheritance for forms and a simple interface. The extracts of the example follows:

The common ancestor class:

type
  TServerForm = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Method1; virtual;
  end;

The interface:

type
  IMyInterface = interface
  ['{B7102C7E-F7F6-492A-982A-4C55CB1065B7}']
    procedure Method2;
  end;

The child forms:

This one inherits from the TServerForm and implements the interface

type
  TServerForm3 = class(TServerForm, IMyInterface)
  public
    procedure Method1; override;
    procedure Method2;
  end;

This one just inherits from TServerForm

type
  TServerForm4 = class(TServerForm)
  public
    procedure Method1; override;
  end;

and this one inherits directly from TForm and implements the interface

type
  TNoServerForm = class(TForm, IMyInterface)
  public
    procedure Method2;
  end;

All the forms are auto-created and then, I have this code to call the methods on a couple of OnClick for buttons on another form (the main form of the application example):

To call the virtual method based on polymorphism:

procedure TForm6.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to Screen.FormCount - 1 do
  begin
    if (Screen.Forms[I] is TServerForm) then
      TServerForm(Screen.Forms[I]).Method1;
  end;
end;

To call the method based on the implementation of the interface:

procedure TForm6.Button2Click(Sender: TObject);
var
  I: Integer;
  Intf: IMyInterface;
begin
  for I := 0 to Screen.FormCount - 1 do
  begin
    if Supports(Screen.Forms[I], IMyInterface, Intf) then
      Intf.Method2;
  end;
end;

The methods just show messages, and everything works fine:

procedure TServerForm3.Method2;
begin
  ShowMessage(ClassName + '.Method2');
end;
like image 159
jachguate Avatar answered Nov 15 '22 06:11

jachguate