2010-04-09 6 views
1

Désolé pour le titre pauvre, je suis nouveau à la POO donc je ne sais pas quel est le terme pour ce que j'ai besoin de faire. J'ai, disons, 10 objets différents qui héritent d'un objet. Ils ont une quantité et un type différents de membres de classe, mais tous ont une propriété en commun - Visible.Comment faire cette OO?

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) 

Pour chacun d'eux j'ai une variable.

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

Règle 1: Seulement un objet peut être initialisé à un moment (les autres doivent être libérés) pour être visible.

Pour cette règle j'ai une variable globale

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

Enfin, il y a une procédure qui change la visibilité.

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; 

Il est mon problème, je ne sais pas comment initialiser, parce que la classe dérivée est inconnue (TObj1, TObj2, Tobj3 ... Lequel?).

Comment faire?

J'ai simplifié l'explication, dans le projet il y a des TFrames ayant chacune des contrôles différents et je dois rendre visible/non visible de la même façon (en ne laissant qu'une seule trame initialisée).

Désolé encore pour le titre, je suis très nouveau à OOP.

Répondre

1

L'un des Le premier problème ici est que vous semblez supposer que vous pouvez passer une variable non initialisée à ChangeObjVisibility.

ChangeObjVisibility(Obj3); 

Ici, si obj3 est nul (ou pire, un pointeur ballants), ChangeObjVisibility n'a aucun moyen de savoir quel est le type de l'objet dont il a besoin pour créer. L'un des moyens de créer une classe de cadre consiste à utiliser un tableau de const ou une fonction avec un cas.

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; 

Cela fonctionnera si le cadre n'a pas besoin d'une initialisation spéciale.

Ensuite, vous pourriez avoir un appel comme celui-ci:

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; 

Ici, SetCurrentFrame vous remplacez ChangeObjVisibility (Ce que vous est vraiment faire ici changer le cadre actuel, en changeant la visibilité est juste un « effet secondaire »

+0

J'ai utilisé un autre moyen en passant le type de classe. Beaucoup mieux je pense, mais ce que vous avez écrit a pris le temps de la vôtre, pour lequel je suis reconnaissant. + 1 & Accepter. –

+0

Passer la classe à ChangeObjVisibility crée des limitations à l'initialisation par classe que vous pouvez avoir. Je préfère passer un objet déjà initialisé au lieu de passer le classtype pour cette raison. Cela rend le design un peu plus flexible. –

0

Vous pouvez accéder à une propriété de base même sur un objet dérivé en raison d'une relation is-a. Dans votre cas, vous voulez avoir un état partagé entre plusieurs objets, une façon d'y penser est de créer une classe de gestionnaire qui va contenir les objets. Il aura seulement un objet sélectionné comme objet visible. Vous n'avez peut-être pas besoin de la propriété visible sur les objets contenus, mais cette conception le permet également.

Conteneur

List MyObjects; Objet MyVisibleObject;

0

Vous ne devriez pas créer et libérer vos cadres chaque fois que vous voulez changer leur visibilité - ils devraient toujours être toujours initialisés tout le temps.

+0

Mais ils valent 30 Mo de mémoire. Et ils sont plus de 10. Je pense que c'est mieux si je les crée chaque fois que je commute entre. –

+1

@John - Je comprends votre point. Nous avons eu un entrepreneur VB qui a construit un grand formulaire de profil client avec des dizaines de cadres, et il suffit de retourner les cadres pour montrer différents types d'informations. Et cela a entraîné le système vers le bas parce qu'il utilisait tellement de ressources. Mais c'était en 1997, avec les processeurs Pentium II, 256 Mo de RAM (peut-être moins? Je ne me souviens pas), et ... Windows 3.1. IMO, étant trop avare avec l'interface utilisateur conduira probablement à des retards excessifs pendant que vous créez/détruire les éléments de l'interface utilisateur. Just sayin ... –

+0

@John: C'est un autre point en faveur de ne pas les allouer et de les libérer à chaque fois! Vous ne voulez pas allouer un gros morceau de mémoire chaque fois que vos utilisateurs changent d'image - cela prendra une éternité. – David

1

S'il s'agit d'un groupe de contrôles TFrame et que vous souhaitez qu'un seul d'entre eux soit visible à la fois, vous n'avez pas besoin d'aller les libérer et de les créer tout le temps. Vous pouvez simplement placer chaque image sur une page d'un TPageControl, puis masquer la bande d'onglets et modifier l'image visible à l'aide de la propriété ActivePage de TPageControl.

+0

+1 Cela peut prendre quelques millisecondes de plus pour démarrer l'application, mais ensuite les choses vont vite et doucement. Un autre avantage est que vous l'état de la trame reste inchangé lorsque vous retournez en arrière. Et comme ça, il est beaucoup plus facile de maintenir l'interface graphique dans l'EDI. –

1

Il est mon problème, je ne sais pas comment pour l'initialiser, parce que la classe dérivée est inconnue (TObj1, TObj2, Tobj3 ... Ce qui un?).

Eh bien, il y a essentiellement deux options:

  • soit vous passez dans le type de l'objet à créer en tant que paramètre à votre méthode, par exemple l'appelant doit vous dire ce qu'il veut créer

  • Vous pouvez déterminer le type à créer à partir d'autres informations; un moyen facile serait de créer un objet du même type que celui que vous avez initialement passé à (ne sais pas si cela fait sens dans votre contexte)

Il a été un moment que je l'ai fait tout travail Delphi sérieux, mais je pense que je me souviens vaguement qu'il existe un moyen Delphi d'exprimer un «type» que vous voulez avoir. Ou peut-être vous êtes même capable de créer une instance d'un type donné basé sur le nom du type comme une chaîne (par exemple créer une instance de TObj2 basé sur la chaîne "TObj2" étant passé)

+0

+ 1, j'ai utilisé First idea.Wish je pourrais ++ plus. :) –