CONNEXION
  • RetourJeux
    • Sorties
    • Hit Parade
    • Les + populaires
    • Les + attendus
    • Soluces
    • Tous les Jeux
    • Gaming
  • RetourActu Gaming
    • News
    • Astuces
    • Tests
    • Previews
    • Toute l'actu gaming
  • RetourBons plans
    • Bons plans
    • Bons plans Smartphone
    • Bons plans Hardware
    • Bons plans Image et Son
    • Bons plans Amazon
    • Bons plans Cdiscount
    • Bons plans Decathlon
    • Bons plans Fnac
    • Tous les Bons plans
  • RetourJVTech
    • Actus High-Tech
    • Intelligence Artificielle
    • Smartphones
    • Mobilité urbaine
    • Hardware
    • Image et son
    • Tutoriels
    • Tests produits High-Tech
    • Guides d'achat High-Tech
    • JVTech
  • RetourCulture
    • Actus Culture
    • Culture
  • RetourVidéos
    • A la une
    • Gaming Live
    • Vidéos Tests
    • Vidéos Previews
    • Gameplay
    • Trailers
    • Chroniques
    • Replay Web TV
    • Toutes les vidéos
  • RetourForums
    • Hardware PC
    • PS5
    • Switch 2
    • Xbox Series
    • Switch
    • Pokemon pocket
    • FC 25 Ultimate Team
    • League of Legends
    • Tous les Forums
  • PC
  • PS5
  • Xbox Series
  • Switch 2
  • PS4
  • One
  • Switch
  • iOS
  • Android
  • MMO
  • RPG
  • FPS
En ce moment Genshin Impact Valhalla Breath of the wild Animal Crossing GTA 5 Red dead 2
Liste des sujets

Grosses classes ou classes dérivée

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 00:32:50

Bonsoir !

Alors voila, j'aimerais avoir des avis sur la question. Supposons une classe A supposée faire des traitements spécifiques en fonction du type de donnée contenu dans une classe B. Est-il préférable de :

1/ Faire une grosse classe pour gérer tous les types en faisant les tests et les cast qui s'imposent selon le type à chaque appel d'une méthode.

2/ Faire des classes dérivées pour chaque type avec constructeurs privés et des méthodes type GetInstance chargées de vérifier si les données en entrée sont bien valides et d'instancier ou non un objet dont on sera en revanche sûr qu'il est fonctionnel derrière.

Merci d'avance. :)

chris_27
chris_27
Niveau 10
22 juillet 2013 à 01:02:14

Bonjour,

je vote pour :

3/ revoir la conception du code.

Et c'est non négociable. Le passage "traitements spécifiques en fonction du ***type***" traduit clairement un mauvaise organisation du code. :non:

Quoiqu'il en soit :
- tu peux écarter le 1 car changer le type d'un objet en cours de route n'est jamais une bonne idée.
- tu peux écarter le 2 car une méthode qui renvoie un type, c'est forcément utilisé pour faire du cast déguisé (enfin, ça peut aussi être du code mort, ce qui est pire encore).

À mon avis, ce que tu veux faire, c'est :
1) transformer B en classe abstraite,
2) ajouter une méthode doSomething virtuelle (éventuellement pure),
3) faire autant d'héritage de B que nécessaire,
4) ne manipuler que des quantités de type B* dans A, sachant que un appel à doSomething dépendra du vrai type de chaque quantité (mais que tu te fous de ce type vu que ce n'est pas toi qui va gérer ça).

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 01:57:06

Bon, avant toute chose, je tiens à préciser (mea culpa, j'avais oublié de le dire) que je bosse en C#, pas en C++.

Ensuite, je ne peux hélas pas faire ce que tu suggère, pour une raison très simple : je ne suis pas responsable de ladite classe B. J'utilise des attributs et la réflexivité, donc je ne peux pas connaitre le type de donnée autrement que par des tests au runtime (vu que la classe B est du coup un FieldInfo ou un PropertyInfo).

Enfin, pour préciser l'archi de mon truc : En gros, t'as AbstractViewer au sommet qui définit une méthode abstraite Show() ainsi que quelques méthodes communes. Les classes dérivées (genre CollectionViewer) possèdent potentiellement un ou plusieurs AbstractViewer. A partir de là, le Show d'un CollectionViewer par exemple fait sa tambouille et pour afficher ses AbstractViewer il a qu'à appeler leur Show().

La question que je me pose concrètement, c'est que pour une CollectionViewer par exemple, c'est un cas spécifique. Mais pour un type primitif, on a pas besoin de grand chose et on pourrait se contenter de faire un PrimitiveViewer qui vérifierait le type dans le Show(). Mais du coup, ça me semble plus propre de vérifier le type une bonne fois pour toutes en instanciant une classe adaptée.

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 12:47:22

Alors du coup, pour quelle solution opteriez vous ?

Un PrimitiveViewer avec une méthode Show() du style :

Type t = finfo.FieldType;

if ( t == typeof(int) )
{
// un truc
}
else if ( t == typeof(float) )
{
// un autre truc
}
else
{
// rien à faire, je notifie l'utilisateur que son type n'est pas supporté
}

Ou alors une factory qui fait ces test et instancie le AbstractViewer adapté qui du coup saura son type et n'aura pas de test sur le type à faire dans son Show() ?

chris_27
chris_27
Niveau 10
22 juillet 2013 à 18:27:17

Désolé, je ne parle pas le C#.

Tout ce que je peux te dire, c'est qu'un (pseudo) code comme ça :

"if ( t == typeof(int) )
{
// un truc
}
else if ( t == typeof(float) )
{
// un autre truc
}
else
{
// rien à faire, je notifie l'utilisateur que son type n'est pas supporté
} "

moi, j'y mets le feu. :diable:

Encore une fois, à chaque fois que tu dis avoir besoin d'un traitement dépendant d'un type, c'est que l'organisation de ton code est foireuse donc à revoir. Ma réponse était assez générique, et je pense qu'il y a moyen de l'appliquer en C# (le cas contraire signifierait selon moi que la couche objet du C# ne servirait à rien, ce dont je doute fort).

Paulop
Paulop
Niveau 12
22 juillet 2013 à 18:32:31

J'ai pas du tout compris ce que tu voulais faire moi.

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 20:41:05

Paulop : Sans aller dans les détails, je cherche à automatiser des procédures via la réflexivité en utilisant des métadonnées fournies par des attributs. Mais ces procédures peuvent énormément varier selon le type pointé.

Chris_27 : Je suis aussi pas partisan des tests à rallonges, qui plus est sur des types. Cependant, dans le cas présent j'utilise la réflexivité donc je vois vraiment pas comment faire autrement que tester le type au runtime pour adopter la bonne procédure. (parce que oui, si mon MemberInfo pointe sur un tableau ou sur un int, je vais pas du tout vouloir faire la même chose au final)

Naturellement, s'il y a un quelqu'un qui est habitué aux langages réflexifs et qui pourraient me conseiller de bonnes pratiques de programmation avec ce paradigme, je suis preneur, vu que je fais surtout ça par curiosité pour voir comment la réflexivité marche.

_skip
_skip
Niveau 10
22 juillet 2013 à 21:05:28

@jenaipasdenom

Peux-tu expliquer ce qui t'empêche d'utiliser une interface dans les classes concernées ou d'encapsuler celle-ci dans des objets dont le rôle est de faire ce traitement dont t'as besoin?

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 21:20:16

Je ne suis pas sûr de comprendre ta question. Est-ce que tu peux expliciter un peu plus s'il te plait ?

Paulop
Paulop
Niveau 12
22 juillet 2013 à 21:21:23

Je ne comprends toujours pas, ton but c'est d'apprendre la reflexivité ? Pourquoi tu fais pas ça avec un truc plus simple ?

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 21:47:09

Parce que j'ai déjà vu les bases, maintenant je me lance sur un micro-projet. (En l'occurrence, mon objectif est de me simplifier la vie quand j'ai besoin de créer des inspecteurs custom dans Unity, pour pas avoir à réécrire trouze mille fois la même chose)

Et franchement, ce que je cherche à faire est vraiment très basique. J'ai pas encore mis le nez dans les fonctionnalités les plus avancées de la réflexivité en C#.

Paulop
Paulop
Niveau 12
22 juillet 2013 à 22:01:46

Comment ils font dans unity pour afficher la bonne vue pour chaque type basique ?

jenaipasdenom
jenaipasdenom
Niveau 15
22 juillet 2013 à 22:13:28

Avec un attribut [SerializeField] pour flaguer les champs de ta classe à sérializer et à afficher dans l'éditeur, donc également la réflexivité. (après, comment ils font précisément en interne pour choisir la bonne vue, j'en sais rien)

Sauf que concrètement ça présente pas mal de limites dès que tu veux faire un truc un minimum custom avec des groupes ou respecter l'encapsulation. Y a bien PimpMyEditor sur l'Asset Store qui fait ça, mais ça me gonfle de payer 10 euros pour un truc que je peux très bien faire moi même en pas trop longtemps en en profitant pour apprendre la réflexivité par la même occasion.

chris_27
chris_27
Niveau 10
23 juillet 2013 à 01:20:56

"Naturellement, s'il y a un quelqu'un qui est habitué aux langages réflexifs et qui pourraient me conseiller de bonnes pratiques de programmation avec ce paradigme, je suis preneur" :d) je crois t'avoir déjà donner la seule bonne pratique.

À moins que tu ne fasses de la preuve de programme semie-automatisée, ou des choses très complexes dynamiquement, je ne vois pas à quoi va te servir la réflexivité.

"je vois vraiment pas comment faire autrement que tester le type au runtime" :d) c'est précisément là que la notion de classe abstraite entre en jeu. Ce n'est pas à *toi* de faire des tests sur les types, mais au compilateur (statiquement si possible, et en ajoutant pour toi les bons tests à effectuer dynamiquement sinon).
Si tu es passé à coté de ça, il y a un problème. :(

jenaipasdenom
jenaipasdenom
Niveau 15
23 juillet 2013 à 01:57:58

"À moins que tu ne fasses de la preuve de programme semie-automatisée, ou des choses très complexes dynamiquement, je ne vois pas à quoi va te servir la réflexivité. "

Je vois pas trop d'autre moyen d'accéder aux métadonnées d'une classe, et vu qu'en l'occurrence mon objectif est de générer dynamiquement une vue de n'importe quelle classe, la question ne se pose même pas à mon sens.

"c'est précisément là que la notion de classe abstraite entre en jeu. Ce n'est pas à *toi* de faire des tests sur les types, mais au compilateur (statiquement si possible, et en ajoutant pour toi les bons tests à effectuer dynamiquement sinon)."

Je dois être très con ou alors j'ai loupé un sacré épisode en cours mais j'arrive toujours pas à comprendre comment se matérialiserait ce que tu m'expliques. :(

Admettons : Je parcours les champs de ma classe qui ont l'attribut [SerializeField]. Je tombe sur un FieldInfo avec un FieldType int, je dois appeler la méthode EditorGUILayout.IntSlider() avec les paramètres qui vont bien. Je suis en présence d'un type float, je dois appeler cette fois la méthode EditorGUILayout.FloatField() et ainsi de suite. Comment je fais pour éviter les tests au runtime ?

godrik
godrik
Niveau 30
23 juillet 2013 à 07:11:50

tu appelles la fonction do_the_right_thing qui en fonction de FieldType appele la bonne fonction de EditorGUILayout.

PS: J'ai pas compris le probleme.

Bunyan
Bunyan
Niveau 17
23 juillet 2013 à 07:37:17

Les classes que tu testes au Runtime, fais-leur implémenter une classe abstraite avec une méthode "doSomethingBasedOnFieldType".

Dans cette méthode, qui est implémentée par chacune des classes que tu tests, tu écris ce qu'elles sont sensées faire.
De l'autre coté, tu as juste à invoquer cette méthode.
Tu manipules des entités qui sont garanties d'avoir implémentées cette méthode, tu n'as pas toi-même à te soucier de ce qu'elles font, c'est à elle qu'échoit la responsabilité de leurs traitements.

jenaipasdenom
jenaipasdenom
Niveau 15
23 juillet 2013 à 11:00:18

"tu appelles la fonction do_the_right_thing qui en fonction de FieldType appele la bonne fonction de EditorGUILayout."

Bah c'est déjà ce que j'ai fait. En fait la question que je me posais d'un point de vue archi était la suivante :

Il y a des cas particuliers à gérer comme les classes ou les collections, où on a pas d'autres choix que de faire une sous-classe d'AbstractViewer à chaque fois parce qu'ils ne sont pas représentés de la même manière coté donnée.
En revanche, un type "primitif", tout ce qu'on a à faire c'est appeler la bonne méthode de EditorGUILayout, pas besoin de membres de classe particulier.

Du coup, je me demandais s'il était préférable de faire un PrimitiveViewer avec une grosse méthode Show() où on test à chaque fois le type et on fait ce qu'il faut. Ou bien faire une factory qui vérifie le type une bonne fois pour toutes et instancie une classe spécialisée pour le type, genre Vector3Viewer. (même si derrière pour nous ce sera un juste un AbstractViewer avec un Show(), donc on se fout de savoir si ça décrit un int, une classe, une collection ou que sais-je encore)

Après, ça n'a peut être aucune importance mais je voulais des avis de dev expérimentés avant d'aller plus loin.

"Les classes que tu testes au Runtime, fais-leur implémenter une classe abstraite avec une méthode "doSomethingBasedOnFieldType". "

Je ne peux pas. Parmi les classes que je test il y a des des types primitifs et des classes internes à l'API d'Unity !

godrik
godrik
Niveau 30
23 juillet 2013 à 17:26:36

Il y a une solution a ce probleme la, tu fais un appel de fonction avec field en parametre et tu fais de la surcharge de fonction pour tous les types primitifs.

jenaipasdenom
jenaipasdenom
Niveau 15
23 juillet 2013 à 22:05:50

Encore une fois, c'est le gros soucis avec la réflexivité, c'est qu'on ne peut pas faire ça (du moins en C#). Le seul moyen de connaitre le type reflété par un FieldInfo est son FieldType qui est un objet Type. Donc la surcharge de méthode ne marcherait pas.

Sous forums
  • Aide à l'achat Mac
  • Création de Jeux
  • Linux
  • Création de sites web
  • Programmation
  • Internet
  • Steam Deck
  • Macintosh
  • Hardware
La vidéo du moment