IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Que penser des frameworks et architectures qui font dériver toutes les classes d'un SuperObjet ?


Sujet :

C++

  1. #41
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Bonjour,

    Cette discussion tombe plutôt bien quand on se pose les questions intimes : Faut-il se mettre à Qt et se coltiner progressivement des héritages de QObjet partout? Comment obtenir un type "souple" pour les algorithmes qui en ont besoin? Comment faire communiquer différentes bibliothèques sans être trop intrusif?

    Citation Envoyé par Luc Hermitte Voir le message
    Sinon, je n'aime pas du tout les god_objets. Je les considère comme des void* qui perdent le typage -- et qui ne peuvent rien nous apporter sur les objets à sémantique de valeur si jamais on voulait profiter des services "divins" de ce void*.
    Il me semble néfaste de voir pulluler les héritages vers un objet Dieu. La seule exception est celui de java : Il est standard, on ne risque pas de vouloir s'en séparer un jour xD. Par contre, on peut souhaiter continuer à faire du C++ si Qt devient obsolète ou de Dot Net si on découvre Qt

    Par contre, comment obtenir la même généricité que ces objets? Pour ma part, il me manque souvent un objet de transfert dont je ne puisse connaitre le type qu'a l'exécution.

    Par exemple, on peut avoir besoin de prendre en entrée un "tableau de points du plan". On veut un "x", un "y" que l'on puisse transformer en double. Savoir si ces points sont des "point2f", des "TPoint<double>", cela ne me regarde pas. Je veux un tableau d'objet possédant des propriétés "x" et "y" de type numérique sur lesquelles je puisse appeler "toDouble" en toute sérénité.

    Pour mettre en place ceci, on se cogne un tas de contrôles, un tas de conversions, la création d'un nouveau type générique ( une union? une structure locale de classe? un void* et un identifiant? un boost::any? un boost::variant? )

    On lit les champs d'une base de données, ben tiens, j'ai rien de mieux qu'un identifiant de type parmi 1000 prédéfinis... Et nous voila reparti pour les contrôles et la mise en place d'un nouveau variant...

    On écrit un point dans une base de données, vaillant, on l'écrit en direct... On écrit ce même point dans un fichier; on met en place une sérialisation; on utilise une bibliothèque externe travaillant sur le point, on ré-introduit une abstraction,...

    En somme, on finit par multiplier les conversions, et se rendre compte que ce qu'il manque, c'est un format d'échange pour les objets que l'on manipule et un poil de généricité.

    On repense à java où l'on pouvait passé Objet en paramètre et appeler instanceof. On regarde un peu plus près java.lang tient Objet et Class... On voit qu'en cherchant bien, il doit être possible de lister les éléments de Class...

    On plonge un peu dans Qt, on voit qu'ils ont un monstre pour la communication QObjet.

    On plonge un peu dans dot net : tiens un Objet...

    Comme l'objet dieu est un anti-pattern au même titre que le copier/coller, j'ai pour ma part envie de prendre la voix d'un troisième : La réinvention de la roue ( ronde quand même! ). L'idée est d'introduire les composants suivant, sur lesquels j'exerce en maître un contrôle ( i.e. loin de nokia, loin de microsoft,... )

    - un variant, type QVariant, mais beaucoup plus limité aux besoins métiers

    -> stockage de types de bases c++ et quelques classes métiers ( image, géométrie, ... ), à base de boost::any.
    -> récupération du type du variant ( avec énumération sur la classe variant )
    -> conversion du variant, vers un type concret, avec contrôle par retour d'un booléen

    - Un tableau de variants :
    -> encapsulation de std::vector< MonVariant >, ou équivalent, et l'interface associée

    - Un objet à base de variant ( type DTO )
    -> une encapsulation de std::map< std::string, MonVariant > et l'interface associée


    A vrai dire, j'ai du mal à trouver mon bonheur dans l'existant. Les composants boost ( variant et any, avec any_cast et lexical_cast ) sont plutôt merveilleux. Seulement, je les trouve d'un peu trop bas niveau. Aussi, le fait de lever une exception pour connaître le type "réel" de "any", où lorsqu'un "lexical_cast" ne passe pas, me déplait.


    QVariant est plutôt "dans mes goût" au niveau de l'utilisation directe de Qt, toutefois, il est pas forcément souhaitable de travailler sur des QImage dans les couches métiers...


    Après, j'avoue avoir baigner beaucoup dans des univers javaïsés, mais je trouve dommage qu'il y ait un tel gap entre le void* et le QObjet ou l'Objet de dot net ( c++/cli )...

    L'objet générique, non pas en temps qu'objet dieu dont toutes classes héritent; mais en temps qu'état, me semble aussi important pour faire communiquer différentes "couches" logicielles; qu'un format d'échange pour faire communiquer différents logiciels.

    Ne faut-il pas un entre deux? Un/des composant(s) d'échange entre les couches métiers, avec les bibliothèques, les frameworks?

    A vous les experts

    Puissiez-vous m'aider à trancher dans mon dilemme : Ce variant et cet Objet tu introduiras; ou pas...

    ps : désolé pour le pavé

  2. #42
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Egalement, le fait d'avoir une hiérarchie unique, si possible sans trop de branches, permet de gérer assez naturellement des pattern composite (widget contenant des widgets), très communs en IHM.
    Il y a une grande nuance entre dire "il y a une classe commune à tous les widgets, permettant de mettre en place le pattern composite sur les widgets" et "il y a une classe commune à tous les objets d'un projet, permettant... permettant quoi d'ailleurs ?"

    Le premier me semble tout à fait acceptable, et normal. Le second, le "god-object" me semble une mauvaise idée.

    Régulièrement, je vois des gens dériver leurs classes métier du QObject de Qt, par exemple (j'ai même vu un singleton en dériver). Et ça me semble un mauvais choix.

    Un argument que je n'ai pas vu, et qui me semble important contre les "god-objects", est qu'une application est rarement monolithique. Comment suis-je sensé faire si ma propre classe se trouve à devoir dériver de QObject parce qu'on utilise Qt, et que dans Qt, tout dérive de QObject, de WObject, parce que si on... de ZSDESObjet, parce que..., sachant que chacune de ces classes implémente sont propre système de signal, de ref counting, d'association à un thread...

    On va se trouver non avec un god-object, mais avec un véritable panthéon, et la mythologie nous a montré moult fois à quel point un panthéon pouvait être bordélique
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #43
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Il y a une grande nuance entre dire "il y a une classe commune à tous les widgets, permettant de mettre en place le pattern composite sur les widgets" et "il y a une classe commune à tous les objets d'un projet, permettant... permettant quoi d'ailleurs ?"

    Le premier me semble tout à fait acceptable, et normal. Le second, le "god-object" me semble une mauvaise idée.
    Dans Qt, dans la VCL, tout ce qui appartient au framework (c'est à dire davantage que les seuls widgets) descend d'un même superobjet. Ce superobjet offre un certain nombre de services transversaux, typiquement, le RTTI (ou une alternative à celui ci), les communications interobjets et la gestion des évènements (via un système de messages)...

    Ces services sont au coeur du framework, on peut choisir de ne pas les utiliser, ou de les refaire, mais c'est un peu contradictoire avec son utilisation : on lutte contre le système...

    Du coup, pour une classe utilisateur, le choix de dériver ou non du superobjet dépend de l'utilisation qu'on a de ces services généraux.

    En pratique, un superobjet qui supporte le système de messages sera la classe de base des éléments d'interface, mais aussi de la plupart des conteneurs de donnée utilisés dans l'application, et probablement aussi des objets "techniques" (qui représentent des threads, ou des applications, ou des périphériques), parce qu'ils doivent généralement être dans la "boucle des messages".

    On peut bien évidemment décider autrement, et doubler le système natif de message d'un autre, mais une fois de plus, on se donne pas mal de travail pour pas grand chose.

    Quant à l'idée d'utiliser plusieurs frameworks, pour disposer de services distincts de leurs "superobjets", elle me parait très perverse. Au fond, un framework, c'est plus qu'une bibliothèque, ca va rendre un certain nombre de services, ca va simplifier pas mal de choses, ca va normaliser le code, mais cela impose un certain nombre de principes...

    Le premier d'entre eux, c'est: "tu n'adoreras qu'un seul framework"...

    Francois

  4. #44
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    je pensais que tu en avais d'autre exemple que boost.
    Pour les signaux/slots il y en a bien sûr d'autres, et pour ce qui est des meta-informations ce n'est de toute façon pas de boost dont je parlais. Par contre désolé, j'ai pas de nom précis en tête.

    vrai. Mais là où boost veut être générique (du simple appel de fonction), Qt se spécialise sur son architecture à base d'eventloop et d'organisation hiérarchisé des QObject. Appeler une fonction dans cette architecture ne veut rien dire. Sauf si on mélange encore le C et le C++....
    Qt ne cherche pas à être boost et rien n'empêche d'utiliser les deux.
    Ok mais la question n'est pas "Qt vs boost", c'est "peut-on offrir des services similaires à QObject sans QObject". Je dis seulement qu'on peut très bien le faire.

    Que veut tu dire par prototype?
    Le types / nombres des paramètres et de la valeur de retour. Par exemple, je ne peux pas connecter un signal qui envoie un int à un slot qui prend un long. Ou encore connecter un slot en fixant l'un de ses paramètres.

    C'est dommage qu'il n'ai pas encore proposé une solution plus propre pour cela. Mais c'est surement pas aussi simple que tu le pense.
    C'est loin d'être simple effectivement mais c'est techniquement faisable, boost.bind le fait.

    Et tu réinvente la roue...Et avoir une eventloop performante et threadsafe c'est pas si simple.
    A ma connaissance seule Qt propose ce type de fonctionnement.
    Là encore on n'essaye pas de remplacer Qt par autre chose, on montre simplement qu'aucune de ces fonctionnalités ne requiert vraiment d'imposer un QObject. Qt est un excellent framework, mais le fait est qu'il pourrait certainement l'être tout autant sans QObject.

  5. #45
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    Qt est un excellent framework, mais le fait est qu'il pourrait certainement l'être tout autant sans QObject.
    Ce qui me pose problème, si l'on enlève le QObject, c'est justement que pour exploiter les systèmes signal/slot, metadata, ... on doit disperser les informations.
    Par exemple dans camp, si j'ai bien compris, tu as un gros singleton qui contient toutes les informations sur les classes qui se sont enregistrées. Comment je pourrais exploiter l'instance d'un objet sans savoir qui il est?
    Le QObject permet cela. Dans un script, quand on ajoute un QObject, le script n'as aucune idée de ce qu'il va manipuler. Mais va appeler les properties et fonctions grâce au metadata. De plus on peut ajouter des propriété dynamique sur un QObject(utilisé par exemple dans un qss(css) pour l'ihm). Je ne voie pas comment garder cette souplesse sans QObject.

    QObject permet aussi une gestion mémoire (par la notion de parent/enfant) très pratique pour faire de l'ihm.

    D'ailleurs seule les classes Qt qui ont besoin de cela hérite de QObject et pas les autres. Faire hériter QVector de QObject se serait débile.

    Y as aussi une autres raison. Une personne (suffisamment) expérimenté puisse se passer d'un superObject, c'est certainement vrai, il ne fera pas n'importe quoi (ou pas...) mais un débutant?
    Pour moi, le superObject permet de créer une base stable, claire et précis à tout un ensemble. Et pour un débutant c'est important.

    Pour moi, non un framework comme Qt, GTK, wxWidget,.net,... ne serait pas aussi puissant et utilisable sans ce superObject.

    Par contre un framework comme boost se serait stupide. C'est pas le même but.


    Et ca veut pas dire qu'il faut hériter du QObject(autre superObjet) parce que l'on utilise Qt.


    [edi]
    une bonne comparaison entre boostSignal et Qt. Pour ce que cela interesse.
    http://www.elpauer.org/stuff/a_deepe..._and_slots.pdf

  6. #46
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par yan Voir le message
    D'ailleurs seule les classes Qt qui ont besoin de cela hérite de QObject et pas les autres. Faire hériter QVector de QObject se serait débile.
    Et même dans ce cas, cela pourrait s'imaginer... D'abord, si les conteneurs du framework peuvent envoyer ou recevoir des messages (descendre de Object les "met dans la boucle", cela remplace un controleur...). Un exemple typique, c'est le cas où tu "virtualises" un tableau ou un arbre de grande taille, en dissociant le conteneur qui détient les données et effectue les recalculs du widget qui en affiche un (tout petit) bout à l'écran. Pouvoir, par le biais de messages, les faire communiquer en direct est un énorme avantage. (Et bien sur, il ne faut pas le faire pour tous les conteneurs de l'appli, sinon bonjour les nouilles au fromage!)

    Ensuite, parce qu'on a souvent une sous classe "objet persistant" juste en dessous du superobjet. Faire descendre les conteneurs de PersistentObject permet d'avoir accès aux fonctions de persistance du framework.

    Citation Envoyé par yan Voir le message
    Par contre un framework comme boost se serait stupide. C'est pas le même but.
    Peut on considérer Boost comme un framework? J'ai l'impression qu'il y a une grande différence entre une bibliothèque (ou un jeu de bibliothèques) comme boost, qui proposent des services relativement découplés, et laissent à l'utilisateur le soin de les assembler, et un framework (le mot anglais veut dire "charpente" je crois qu'il est très bien trouvé) qui propose des services intégrés à une hiérarchie de classe, et impose donc une "manière de faire".

    Le cas de la persistance, mentionné plus haut, est typique. Dans une librairie, on en fait une classe à part, destinée à être intégrée sous forme de policy, dans un framework, on en fait un niveau de la hierarchie d'objets.

    Francois

  7. #47
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Et même dans ce cas, cela pourrait s'imaginer... D'abord, si les conteneurs du framework peuvent envoyer ou recevoir des messages (descendre de Object les "met dans la boucle", cela remplace un controleur...). Ensuite, parce qu'on a souvent une sous classe "objet persistant" juste en dessous du superobjet. Faire descendre les conteneurs de PersistentObject permet d'avoir accès aux fonctions de persistance du framework.
    j'ai du mal à voir en quoi connecter un objet sur un QString, QVector, QImage,... peut être intéressant :
    * c'est structure sont généralement là pour être manipuler énormément de fois. Cela ferais des emit de signal à foison .
    * a la limite pour le slot. Pouvoir faire un clear sur un conteneur ou l'exploiter dans un script... mais ça me parait contre productif (perte de performance énorme).

  8. #48
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par yan Voir le message
    j'ai du mal à voir en quoi connecter un objet sur un QString, QVector, QImage,... peut être intéressant :
    Si tu regardes la VCL, tu verras que tu as PLUSIEURS "objets" de base, et pas seulement un TObject... Le TObject est plus ou moins réservé aux objets destinés à l'IHM elle-même, les containers n'en dérivent pas forcément.

    Le but n'est pas forcément d'avoir une racine unique, mais un jeu de racineS très, très réduit.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #49
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par yan Voir le message
    j'ai du mal à voir en quoi connecter un objet sur un QString, QVector, QImage,... peut être intéressant :
    Typiquement quand tu affiches un document complexe, fondé sur un très gros conteneur, et quand la structure du conteneur et celle de la vue sont assez différentes. La séparation vue conteneur permet de découpler les aspects calculs (que tu peux traiter par lot) des aspects interface (le scrolling, les détails de formatage, l'allocation des seuls éléments visibles de l'interface, et la désallocation de ceux qui ne le sont pas). Ca simplifie beaucoup le code métier...

    Maintenant, si ce découplage est utile au programmeur, il doit rester invisible à l'utilisateur... Si les deux composants sont intimement liés (par exemple si un survol, un clic, un changement de taille de colonne, provoquent des recalculs lours, et si la vue n'affiche qu'un tout petit bout du conteneur), il va falloir établir un système de communication rapide et précis entre les deux. Un système de messages adhoc est souvent la meilleure solution pour ne pas trop perdre en efficacité (mais on ne passe bien sur pas TOUS les messages, sinon, à quoi bon découpler...).

    Un autre aspect assez typique, c'est quand les widget d'interface utilisent les conteneurs standards du framework pour stocker leur données. Chez Borland, les listes de chaines TStrings sont absolument partout (pour stocker les chaines d'un mémo, les enfants d'une fenêtre, les entrées d'un radiogroup, etc...). Leur permettre d'émettre des messages (OnAdd, OnChange, etc..) qui sont alors transmis à leurs parents simplifie nettement le code. Je suis à peu près certain que Qt a un type similaire.

    @Mac Lak : dans la VCL, je crois que TOUT descend de TObject (les TList, même les Exceptions). Je pense qu'il y a deux raisons à cela :

    -le Delphi (et le C++ des débuts) supportait mal le RTTI
    -TObject fournit un certain nombre des éléments qui permettent à l'EDI de gérer la VCL (on est dans un cas étrange où le code est partiellement interprété par l'EDI)

    Francois
    Dernière modification par Invité ; 04/03/2010 à 12h29.

  10. #50
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par fcharton Voir le message
    @Mac Lak : dans la VCL, je crois que TOUT descend de TObject (même les Exceptions). Mais je crois que cela tient au fait que Delphi (et le C++ des débuts de ce framework) supportait mal le RTTI... Et là, pour avoir un RTTI, un objet parent ultime, c'est quand même drolement simpmle.
    Faudra que je vérifie (je n'ai pas Delphi sous le coude à cet instant précis), mais il y a des exceptions, il me semble... Notamment pour les chaînes, au minimum.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  11. #51
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Faudra que je vérifie (je n'ai pas Delphi sous le coude à cet instant précis), mais il y a des exceptions, il me semble... Notamment pour les chaînes, au minimum.
    Je viens de regarder... Effectivement: tous les types de base qui sont en fait des portages de types natifs delphi (typiquement ce qui se trouve dans System) sont hors hiérarchie (TDateTime, AnsiString, Variant, ...).

    Les conteneurs tels que TList et TCollection sont eux dans la hiérarchie TObject.

    Francois

  12. #52
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Les conteneurs tels que TList et TCollection sont eux dans la hiérarchie TObject.
    Merci pour le "zieutage", je savais bien que je n'étais pas fou...

    Il y a aussi une grosse subdivision dans la hiérarchie TObject, si je me souviens bien, entre TControl (racine du système "graphique") et TComponent (racine des éléments connexes, mais non-graphiques).
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  13. #53
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Il y a aussi une grosse subdivision dans la hiérarchie TObject, si je me souviens bien, entre TControl (racine du système "graphique") et TComponent (racine des éléments connexes, mais non-graphiques).
    Oui, en fait, ca s'organise comme ça :

    - tout en haut tu as TObject, c'est la racine, ca gère les messages, et les infos sur le type. Les Exceptions, les TList (listes de pointeurs) les TIniFile et autres TPrinter

    - juste en dessous, TPersistent, qui gère la notion de properties, et le streaming des données (donc des trucs pour l'EDI, en fait). C'est ici que se rattachent un certain nombre de classes que les widgets d'interface utilisent (et qui sont écrits dans les forms) TBrush, TPen, TFont, TCanvas, TCollection, TStrings, TBitmap

    - encore en dessous, TComponent, qui est la classe de base des composites. C'est là que sont définies les propriétés Owner et Components. En dérivent directement des composants non visuels (TTimer) mais aussi des composants proches du système (TMainMenu, TScreen, TApplication, TOpenDialog), qui sont traités hors de la hiérarchie d'interface classique

    - ensuite, tu trouves TControl et TGraphicControl, où se trouvent les principaux composants visuels. C'est là que sont introduites les notions de hiérarchie d'affichage (via la propriété Parent), et les premieres propriétés graphiques (Color, Caption), et la gestion des interactions souris. Mais les TControl ne sont pas réellement fenêtrés (pas de handle de fenêtre), ne reçoivent rien du clavier, et ne peuvent servir de "conteneurs visuels".

    - enfin, on a TWinControl (TWidgetControl en CLX, je crois), qui correspond à la notion "habituelle" de composant visuel.

    Je crois que la hiérarchie de Qt est assez similaire.

    Cette hiérarchie sert à découper en 'classes fonctionnelles', mais aussi définit les niveaux d'interface avec l'API de l'OS (c'est le role de TWinControl), et fournit à l'EDI les concepts communs dont il a besoin.

    C'est à mon avis la vraie particularité de Borland : l'EDI fait un peu partie du langage...

    Francois

  14. #54
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par fcharton Voir le message
    C'est à mon avis la vraie particularité de Borland : l'EDI fait un peu partie du langage...
    Comme dans tout bon RAD, en fait...

    Cette interaction forte entre l'IDE et le code est requise si l'on veut un RAD digne de ce nom. Et, franchement, une fois que l'on y est habitué, il devient difficile de revenir à un système "roots" (dans lequel je mets allègrement le développement MFC) qui ne t'aide que très partiellement dans la création d'éléments graphiques.


    Ce qui me fait dire, effectivement, que si ce genre de hiérarchie n'est pas forcément utile (voire carrément non souhaitable) sur des librairies "d'outillage" comme STL ou Boost, ce n'est pas du tout la même chose avec un système RAD qui DOIT pouvoir contrôler et vérifier TOUS les objets insérés graphiquement. Et c'est peut-être là la source initiale de la discussion, d'ailleurs : personne (à part une remarque rapide de koala01) n'a pris en compte l'aspect RAD, jusqu'à présent.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  15. #55
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ce qui me pose problème, si l'on enlève le QObject, c'est justement que pour exploiter les systèmes signal/slot, metadata, ... on doit disperser les informations.
    En quoi est-ce un inconvénient ? Si je veux les meta-informations sur un objet je vais le demander au système de meta-information, si je veux que mon objet gère des signaux je lui en mets en données membres, etc. Et ce qui ne m'intéresse pas, je ne le trimballe pas via une grosse classe de base.

    Par exemple dans camp, si j'ai bien compris, tu as un gros singleton qui contient toutes les informations sur les classes qui se sont enregistrées. Comment je pourrais exploiter l'instance d'un objet sans savoir qui il est?
    Je ne comprends pas bien ta remarque. CAMP fournit tout ce qu'il faut par rapport à l'objet, mais simplement il le fait de manière externe (non intrusive), pas via des choses hérités que l'objet aurait hérité d'une classe de base. Là encore, l'objet en lui-même reste "clean" et tout ce que je lui rajoute comme fonctionnalité supplémentaire ne vient pas le polluer.

    QObject permet aussi une gestion mémoire (par la notion de parent/enfant) très pratique pour faire de l'ihm.
    J'ai toujours des problèmes car je ne sais jamais si c'est moi ou Qt qui a la responsabilité de tel ou tel objet. C'est assez perturbant parfois. Et puis ça peut se gérer dans une classe de base de widget, pas besoin d'aller aussi haut que le QObject.

  16. #56
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    Je ne comprends pas bien ta remarque. CAMP fournit tout ce qu'il faut par rapport à l'objet, mais simplement il le fait de manière externe (non intrusive)
    Justement. Cette manière t'oblige à connaitre le type de l'objet pour exploiter les metadata. Tu peut pas en faire abstraction.

    QObject te permet de découvrir les propriétés et fonctions d'une instance sans savoir au préalable sa nature.
    C'est ce qui permet à Qt de faire interagir du javascript avec n'importe quel QObject.
    Par exemple, comment ferais tu une éditeur dynamique de propriété dans ce contexte?

    Pour moi la réflexion ne sert pas qu'à accéder aux propriétés/fonction d'une classe d'un autre manière, mais de faire abstract de sa nature et permettre de découvrir dynamique ce qu'elle propose.

  17. #57
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    CAMP a bien évidemment lui aussi un moyen de trimballer un objet sans connaître son type, sinon la bibliothèque tout entière perdrait son intérêt

    La différence c'est que ce n'est pas une classe de base, c'est une classe externe qui vient encapsuler l'objet et lui associer ses meta-informations.

  18. #58
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    CAMP a bien évidemment lui aussi un moyen de trimballer un objet sans connaître son type, sinon la bibliothèque tout entière perdrait son intérêt

    La différence c'est que ce n'est pas une classe de base, c'est une classe externe qui vient encapsuler l'objet et lui associer ses meta-informations.
    Si j'ai bien compris comment fonctionne CAMP :
    1- faut enregistrer la classe et ses meta data dans un singleton
    2- à partir du nom ou du typeId tu peut accéder au metadata par un CAMP:Class
    3- l'instance est en-capsulée dans une sort de boost::any : UserObject.
    4- il faut que l'instance encapsulée par UserObject soit du bon type pour être exploitée par CAMP:Class
    5- dans le cas d'héritage on n'accède qu'au metadata que CAMP:Class permet
    d'accéder et rien d'autre.
    6-il faut un CAMP:Class compatible pour exploiter les metadata sur une instance
    7- Que se passe t'il si le UserOject n'est pas compatible avec la camp::Class utilisé? Une exception? ceci est validé à la compile?

    Qt avec QObject :
    1- les metadata sont défis directement dans la définition de la classe grâce au moc
    2- les metadata sont directement accessible par l'instance
    3- les metada sont hérités et on as pas besoin de connaitre le type.
    4- on peut ajouter des propriétés dynamiquement.


    Grâce au superObject, je trouve que la version Qt bien plus simple et permet des choses que ne permet pas camp( Et camp permet des choses que ne permet pas QObject). De là à dire que la version de CAMP est plus puissante ou inversement , je dit que c'est comme avec les signal/slot, c'est pas le même objectif.

    Pour moi le superObject permet de simplifier la compréhension et l'utilisation.

  19. #59
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par fcharton Voir le message
    Maintenant, si ce découplage est utile au programmeur, il doit rester invisible à l'utilisateur... Si les deux composants sont intimement liés (par exemple si un survol, un clic, un changement de taille de colonne, provoquent des recalculs lours, et si la vue n'affiche qu'un tout petit bout du conteneur), il va falloir établir un système de communication rapide et précis entre les deux. Un système de messages adhoc est souvent la meilleure solution pour ne pas trop perdre en efficacité (mais on ne passe bien sur pas TOUS les messages, sinon, à quoi bon découpler...).
    C'est moi où tu es simplement en train de décrire MVC ? (et surtout MC/V, en fait). C'est typiquement ce que fait Qt (depuis la version 4), mais en passant par un adapteur entre la collection et le widget (le modèle, justement). Et ça me semble plus raisonnable que de vouloir intégrer directement les messages dans le conteneur.

    Un autre aspect assez typique, c'est quand les widget d'interface utilisent les conteneurs standards du framework pour stocker leur données. Chez Borland, les listes de chaines TStrings sont absolument partout (pour stocker les chaines d'un mémo, les enfants d'une fenêtre, les entrées d'un radiogroup, etc...). Leur permettre d'émettre des messages (OnAdd, OnChange, etc..) qui sont alors transmis à leurs parents simplifie nettement le code. Je suis à peu près certain que Qt a un type similaire.
    Qt passe par le modèle, avec les avantages que ça apporte (gestion beaucoup plus fine des évènements puisque complètement gérable par l'utilisateur) pour gérer ça.

  20. #60
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    C'est moi où tu es simplement en train de décrire MVC ? (et surtout MC/V, en fait). C'est typiquement ce que fait Qt (depuis la version 4), mais en passant par un adapteur entre la collection et le widget (le modèle, justement). Et ça me semble plus raisonnable que de vouloir intégrer directement les messages dans le conteneur.
    Ce n'est pas un modèle et une vue. Le conteneur dont je parle fait partie de la vue. Au dessus, il y a un modèle, qui remplit le conteneur, et communique via un controleur ou quelque chose du genre. Tant que le conteneur est suffisamment simple pour qu'on puisse considérer qu'il fait partie du widget (eg la liste d'une combobox), ou que les données qu'il contient sont suffisamment simples pour qu'on puisse les considérer comme partie du modèle (eg les données d'une grille, qui liste les enregistrements d'une table), le choix technologique (données dans le modèle ou dans le widget) n'a aucune importance.

    Là où ca se complique, c'est quand les données gérées par la vue augmentent en nombre et en complexité, quand la vue ne doit pas (pour des raisons de performance) afficher toutes les données du conteneur, ou quand la vue effectue des calculs spécifiques (par exemple, autour du formattage, de la totalisation des données qu'elle présente). Tu as alors deux choix :

    1- remonter tous les calculs dans le modèle, en compliquant celui ci, pour garder la vue "idiote"
    2- rendre la vue un peu plus intelligente, en lui laissant faire des calculs, de manière à mieux répartir la charge entre elle et le modèle

    Dans le premier cas, tu vas rapidement encombrer ton controlleur de messages très proches de l'IHM, et faire transiter toutes sortes de calculs basiques que la vue peut faire elle même (différences, pourcentages, totalisations).

    Les "messages conteneurs" sont utiles dans le second cas. D'une certaine manière, tu considères ta vue comme un mini MVC. Ce n'est bien sur pas à faire systématiquement, mais sur des applis qui gèrent de gros volumes de données, c'est généralement bien plus efficace que de tout remonter dans le modèle.

    Une fois de plus, la méthode que tu proposes est presque toujours la bonne, et elle doit être la solution par défaut. Je dis simplement que garder les conteneurs dans la boucle de messages, ca ne sert pas souvent, mais ca donne à ton framework une puissance supplémentaire, en permettant de travailler avec des vues plus puissantes que les listbox et les grid de base...

    Francois

Discussions similaires

  1. Réponses: 36
    Dernier message: 12/01/2011, 15h55
  2. Que penser des testeurs de Carte Mère
    Par Fabdeuche dans le forum Ordinateurs
    Réponses: 1
    Dernier message: 26/11/2010, 10h35
  3. Réponses: 0
    Dernier message: 15/11/2010, 11h51
  4. Un programme qui lance quelquechose toute les 50 minutes?
    Par altadeos dans le forum C++Builder
    Réponses: 4
    Dernier message: 12/03/2006, 11h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo