Question

Si j'implémentent une interface sur une classe de base sera elle héritée par ses sous-classes, je sais que les fonctions / procédures seront, mais je suis plus intéressé à savoir si je serai en mesure de lancer la sous-classe à l'interface, puis à sa classe d'origine.

Ce que j'espère que je peux faire est des objets passe de différentes classes de base à une fonction, puis dans la fonction détermi type et il les utiliser selon le cas.

Est-ce possible et est-ce la bonne approche?

Mise à jour

pour aider à éliminer toute confusion (ou de créer un peu plus) est ici ce que je voudrais faire (rayé jusqu'à son noyau).

Interface

    IMyInterFace = interface
   ['{B7203E50-F5CB-4755-9DB1-FB41B7B192C5}'] 
     function MyFunction: Boolean;
   end;

classe de base

   type TMyObject = class(TInterfacedObject,IMyInterFace)

Sous classe

  type TSubMyObject = class(TMyObject)

Une autre classe

  type TMyOtherObject = class(TInterfacedObject,IMyInterFace)

Ensuite, l'utilisation

 procedure foo();
   var obj:TSubMyObject;
 begin
      obj := TSubMyObject.Create();
      SendInterfaceObject(obj);
 end;

 procedure bar();
   var obj:TMyOtherObject;
 begin
      obj := TMyOtherObject.Create();
      SendInterfaceObject(obj);
 end;



 procedure SendInterfaceObject(iobj:IMyInterFace);
 begin
     if (iobj is TSubMyObject) then
     begin
        //code here
     end
     else if (iobj is TMyOtherObject) then
     begin
       //code here
     end;
 end;

Mise à jour 2

Je l'ai mis à jour le abit code pour montrer ce que je suis après mieux.

// code ici sections ont peu à voir avec l'objet qui lui sont transmis, par exemple, si cette classe est TAccounts et il a été adopté un objet TEmployee il peut verser une indemnité y hebdomadaire, mais si elle était un TInvoice il vérifierait si elle avait besoin de payer et ne payez que lorsque la date était de 2 jours avant la date limite.

le TEmployee / TInvoice peut même venir des classes secondaires sur demande pour les paiements à effectuer.

est juste un exemple.

Était-ce utile?

La solution

Oui, l'interface est héritée par la sous-classe.

Il est parfaitement acceptable de jeter de la sous-classe à l'interface.

Cependant, et excuses si je lis votre mauvaise question, mais si « et à sa classe d'origine » moyens. . .

Vous avez interface I, classe A et classe B. A outils I et B hérite d'une, vous pouvez peut-être, mais VRAIMENT NE DOIT PAS jeter de A à B.

EDIT:

Vous voulez aller de B à I et revenir à B. . . mais vous avez déjà une référence à B, si B est ce que vous passez à votre fonction, de sorte que vous n'avez pas besoin de jeter de I à B (sauf si on parle d'un objet différent, Non, ne le faites pas)

Voulez-vous profiter de I à B est le même que celui allant de A à B, vous essayez de lancer la chaîne d'héritage, ce qui est vraiment quelque chose que vous ne devriez pas faire. Ayant besoin de faire est une odeur de code, il vous dit que vous devriez essayer de résoudre ce problème d'une manière différente (peut-être par vous redessiner les classes (par exemple l'ajout de propriétés / méthodes I), ou tout simplement décider que la fonction ne fonctionnera que avec la sous-classe - travail avec la sous-classe B »vous donnera accès à toutes les méthodes de A & I)

.

Pouvez-vous modifier votre question et ajoutez quelques exemples de code de ce que vous essayez de faire?

EDIT 2

 procedure SendInterfaceObject(iobj:IMyInterFace);
 begin
     if (iobj is TSubMyObject) then
     begin
        //code here
     end;
 end;

Les « Si » déclaration il y a une mauvaise idée, et les pauses principaux OO. Si vous avez besoin de le faire alors soit

  • La définition d'interface est insuffisant, vous pouvez ajouter un Type de propriété à l'interface vous permettant de (si iObj.SomeProperty = 1) alors. . .)
  • L'interface est tout simplement pas le correct Soluton à ce problème, et vous devez passer la référence TSubMyObject.

EDIT 3:

@mghie: Je suis d'accord avec vous, ce que je n'ai pas expliqué très bien est que SomeProperty a des données qui permet à la fonction de succursale, la suppression du contrôle de dépendance de type. SomeProperty ne doit pas « simplement » remplacer le contrôle de type (par exemple en plaçant le nom de classe dans une propriété, puis vérifier le nom de classe) C'est en effet exactement le même problème.

Il y a une différence essentielle entre les sous-classes héritant de l'interface. Cette différence doit être exprimée soit par

  • Exposer un certain élément de données qui peuvent puis être utilisé dans le Brach

par exemple.

if(item.Color = Red) then 
   item.ContrastColor := Blue;
else
   item.ContrastColor := Red;
  • Ou par polymorphisme par exemple.

iEmployee définit une méthode de CalculatePay, TManager et TWorker mettre en œuvre iEmployee, chacun avec une logique différente dans les méthodes de CalculatePay.

Si l'intention était de faire quelque chose comme le premier cas, le polymorphisme peut être surpuissant (polymorphisme ne résout pas tous les problèmes).

EDIT 4

Vous dites « les sections code // ici ont peu à voir avec l'objet qui lui sont transmis... » Je suis désolé mais cette déclaration est incorrecte, si vous devez payer un employé, vous avez besoin de connaître leurs 1) EmployeeCode 2) leur salaire détails 3) leurs coordonnées bancaires etc, si vous chargez une facture dont vous avez besoin 1) InvoiceNumber 2) Montant de la facture 3) CustomerCode pour charger à etc. . . c'est un endroit idéal pour Polymorphisme .

Disons que la fonction de prendre les contrôles d'interface pour voir si « Comptes » doit faire quelque chose avec l'objet (par exemple payer l'employé, la charge d'une facture, etc.). On peut donc appeler la fonction AccountsCheck. A l'intérieur des comptes de vérifier que vous avez un morceau de logique propre à chaque sous-classe (à payer un employé, pour charger la facture...) Ceci est un candidat idéal pour Polymorphisme.

vous interface (ou sur une autre interface, ou comme méthode virtuelle sur la sous-classe) Définir une méthode « AccountsCheck ». Ensuite, chaque classe dérivée obtient vérifier sa propre implémentation de comptes.

Le code se déplace de votre humungous seule fonction AccountsCheck, et en plus petites fonctions de chaque classe sous. Cela rend le code

  • Plusdans l'intention évidente (chaque classe contient une certaine logique pour AccountsCheck)
  • Vous êtes moins susceptible de casser SubClass la logique de B au moment de fixer quelque chose AccountsCheck C
  • Il est plus facile de comprendre exactement ce que la logique B SubClass AccountsCheck est, vous avez seulement vérifier 20 lignes de le code dans un petit AccountsCheck, pas 200 dans la AccountsCheck générale)

Il y a plus, « bonnes raisons » pour cela, aif uiconque souhaite modifier / poster des commentaires s'il vous plaît le faire.

Si vous vous trouvez besoin de partager une certaine logique entre les implémentations de AccountsCheck, créer des fonctions d'utilité, ne réimplémentez pas la même roue dans chacun.

polymorphisme est la solution à votre problème.

Autres conseils

Ma suggestion serait ici de ne pas jeter contre la classe mais heurtez une autre interface. Changez votre TMyOtherObject à:

type
  IOtherObjectIntf = interface
    ['{FD86EE29-ABCA-4D50-B32A-24A7E71486A7}']
  end;

type 
  TMyOtherObject = class(TInterfacedObject,IMyInterFace,IOtherObjectIntf)

puis changer votre routine autre comme suit:

procedure SendInterfaceObject(iobj:IMyInterFace);
begin
  if Supports(iObj,IOtherObjectIntf) then
    begin
      //code here for TMyOtherObject
    end
  else 
    begin
      //code here for other standard implementations
    end;
end;

De cette façon, votre code « personnalisé » pour la TMyOtherObject serait appliquée également à tous les descendants ITS sans autre code personnalisé. L'interface IOtherObjectIntf est utilisée comme rien d'autre qu'un « Eh oui, je suis l'un de ces » indicateurs qui permet à votre code correctement mis. Bien sûr, ses déchets ponte à l'autre Guid ... mais il y a tellement d'entre eux, qui remarquerait? :)

L'interface est héritée par les sous-classes et vous pouvez jeter les objets à l'interface, mais il est pas sûr (ou recommandé) pour lancer l'interface à la classe. Si vous devez faire, vous utilisez probablement des interfaces dans la mauvaise direction.

Il semble y avoir un doute sur la façon dont votre question doit être compris, et même dans votre commentaire à cette réponse vous dites que vous voulez "passer de B à I B".

Ceci est en effet pas recommandé et pris en charge uniquement en utilisant des informations sur la façon dont les interfaces sont mises en œuvre sur une classe.

Si je vous comprends bien alors ce que vous voulez faire est de passer d'une interface à une méthode, et cette méthode faire des choses différentes en fonction de quelle classe concrète l'interface a été mis en œuvre par. Il est cependant préférable de continuer à utiliser des interfaces une fois que vous commencez avec eux. Vous pourrait laisser l'interface ont une méthode pour retourner la classe d'implémentation, mais vous ne devriez pas faire des hypothèses sur ce qui classe l'interface est mise en œuvre -. Il vous coûte quelques-uns des avantages de la programmation contre les interfaces

Qu'est-ce que vous pouvez faire à la place est de créer des interfaces différentes, et mettre en œuvre certains d'entre eux seulement (certaines) vos classes descendantes. Ensuite, vous pouvez utiliser QueryInterface () ou Supports () sur le pointeur d'interface passé. Pour votre classe de base ce sera de retour nil , mais pour toutes les classes descendantes qui mettent en œuvre l'interface, il renvoie un pointeur qui vous permet d'appeler les méthodes seulement ils ont.

Modifier Par exemple, dans le OmniThreadLibrary, vous trouverez:

IOmniWorker = interface
  ['{CA63E8C2-9B0E-4BFA-A527-31B2FCD8F413}']
  function  GetImplementor: TObject;
  ...
end;

que vous pouvez ajouter à votre interface. Mais encore une fois, à mon humble avis l'utilisation d'interfaces distinctes est beaucoup mieux.

Vous ne pouvez pas lancer une interface à un objet directement (il n'est pas ce que les interfaces sont destinées à) mais parfois si pratique pour être en mesure de le faire, que vous ne pouvez pas résister ...

Si vous voulez vraiment faire comme ça, vous pouvez utiliser l'exemple « IOmniWorker » donnée par mghie directement IMyInterface:

IMyInterFace = interface
['{B7203E50-F5CB-4755-9DB1-FB41B7B192C5}'] 
  function MyFunction: Boolean;
  function GetImplementor: TObject;
end;

Les implémentations de fonction qui ressemblent à:

function TMyObject.GetImplementor: TObject;
begin
  Result := Self;
end;
function TMyOtherObject.GetImplementor: TObject;
begin
  Result := Self;
end; 

SendInterfaceObject regarde alors comme ça:

procedure SendInterfaceObject(const iobj:IMyInterFace);
begin
  if (iobj.GetImplementor is TSubMyObject) then
  begin
     //code here
  end
  else if (iobj.GetImplementor is TMyOtherObject) then
  begin
    //code here
  end;
end;

Par la façon dont j'ai ajouté une petite (très) optimisation. En passant iobj comme « const » à la fonction que vous pouvez éviter le comptage de références inutiles

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top