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 :

Singleton & Smart_pointer


Sujet :

C++

  1. #1
    Membre régulier
    Homme Profil pro
    .
    Inscrit en
    Octobre 2014
    Messages
    174
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : .
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2014
    Messages : 174
    Points : 90
    Points
    90
    Par défaut Singleton & Smart_pointer
    Bonjour,

    Le tuto n'offre pas de solutions pour réaliser des singletons en passant par des smart pointer.
    Comment peut-on s'y prendre?

    Actuellement mes tests donne:

    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    class Ressources_Manager : boost::noncopyable{
    public:
    	static boost::shared_ptr<Ressources_Manager> Instance();
    	virtual ~Ressources_Manager();
     
     
    private:
    //	boost::shared_ptr<Ressources_Manager> operator= (const boost::shared_ptr<Ressources_Manager>){}
    	Ressources_Manager();
    	Ressources_Manager (const Ressources_Manager&);
     
    	static boost::weak_ptr<Ressources_Manager>  m_instance;
     
    	sf::Texture H_Sp_Prairie;
    	sf::Image   Img_H_Prairie;
     
    	void Load_Textures();
    	void Load_Images();
    };


    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    	boost::shared_ptr<Ressources_Manager> Ressources_Manager_ptr = Ressources_Manager::Instance();
    //	Ressources_Manager Ressources_Manager::m_instance=Ressources_Manager();
     
    		Ressources_Manager::Ressources_Manager() {
     
    			Load_Images();
    			Load_Textures();
    		}
     
    		Ressources_Manager::~Ressources_Manager() {
     
    		}
     
    		boost::shared_ptr<Ressources_Manager> Ressources_Manager::Instance()
    		{
     
    			  boost::shared_ptr<Ressources_Manager> instance = m_instance.lock();
    			  if (!instance) {
    			    instance.reset(new Ressources_Manager());
    			    m_instance = instance;
    			  }
    			return instance;
    		}
     
    		void Ressources_Manager::Load_Images()
    		{
    			Img_H_Prairie.loadFromFile("Image/HexaTestSize.bmp");
    			Img_H_Prairie.createMaskFromColor(sf::Color(255,255,255));
    		}
     
    		void Ressources_Manager::Load_Textures()
    		{
    			H_Sp_Prairie.loadFromImage(Img_H_Prairie);
    		}

    Erreur affichée:
    ../RessourcesManager.cpp:29: undefined reference to `itpro::ress::Ressources_Manager::m_instance'

  2. #2
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 031
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 031
    Points : 11 474
    Points
    11 474
    Billets dans le blog
    11
    Par défaut
    Bon, pour commencer, ton instance ne devrait pas être stockée dans un weak_ptr, car une fois sorti de ta fonction Instance(), le shared_ptr est détruit, et comme il est la seule strong reference sur l'instance, celle-ci est détruite.
    Ensuite, utilise boost::make_shared plutôt que ptr.reset( new... ).
    Pour ton erreur de link, c'est simplement dù au fait que tu déclarais m_instance en tant que weak_ptr et tu l'implémentais en tant que shared_ptr


    EDIT:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	boost::shared_ptr<Ressources_Manager> Ressources_Manager_ptr = Ressources_Manager::Instance();
    //	Ressources_Manager Ressources_Manager::m_instance=Ressources_Manager();
    Que cherches-tu à faire là? Pourquoi m_instance a-t-elle changé de nom?
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    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
    Je ne suis pas certain que singleton et shared pointers aillent bien ensemble (sans compter que le singleton st souvent un anti-pattern) : Tu va avoir un singleton qui va être détruit dès que personne ne l'utilise, et se reconstruire à chaque utilisation. Difficile dans ces cas là de garder de l'état d'une utilisation à l'autre, et sans état à garder et à partager, à quoi sert un singleton ?

    Pour ton problème de link, j'imagine que c'est parce que tu as déclaré ta variable statique dans ton .h, mais que tu ne l'as définie nulle part. Ajoute dans ton .cpp:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::weak_ptr<Ressources_Manager>  Ressources_Manager::m_instance;
    http://cpp.developpez.com/faq/cpp/?p...tion-des-liens

    Sinon, ta fonction Instance n'est pas thread-safe : Qu'arrive-t-il si, alors que ton weak_ptr est vide, deux personnens demandent simultanément accès à Instance ? Tu risques de créer deux shared_ptr différents...
    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.

  4. #4
    Membre régulier
    Homme Profil pro
    .
    Inscrit en
    Octobre 2014
    Messages
    174
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : .
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2014
    Messages : 174
    Points : 90
    Points
    90
    Par défaut
    Bonjour,

    Merci pour vos réponses,
    En faite je n'ai pas besoins d'utiliser des threads pour cette class, mais je souhaite en faire un singleton pour ne l'initialisée q'une seule fois et pouvoir l’instancier un peut partout dans mon projet comme s'il s'agissait d'une variable globale.
    Je me suis un peut aventuré avec les weak_ptr sans savoir ou j'allais en suivant un code trouvé sur internet.
    En revanche je souhaiterais vraiment faire appel aux smart_ptr soit les shared_ptr pour partager cette classe avec les autres ressources de mon programme.
    Je n'ai pas encore trouvé la solution.

    Merci à vous

  5. #5
    Membre régulier
    Homme Profil pro
    .
    Inscrit en
    Octobre 2014
    Messages
    174
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : .
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2014
    Messages : 174
    Points : 90
    Points
    90
    Par défaut
    Pb résolue,

    Merci à vous

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Hyssgrif Voir le message
    Bonjour,

    Merci pour vos réponses,
    En faite je n'ai pas besoins d'utiliser des threads pour cette class, mais je souhaite en faire un singleton pour ne l'initialisée q'une seule fois et pouvoir l’instancier un peut partout dans mon projet comme s'il s'agissait d'une variable globale.
    Je me suis un peut aventuré avec les weak_ptr sans savoir ou j'allais en suivant un code trouvé sur internet.
    En revanche je souhaiterais vraiment faire appel aux smart_ptr soit les shared_ptr pour partager cette classe avec les autres ressources de mon programme.
    Je n'ai pas encore trouvé la solution.

    Merci à vous
    Je me permet de revenir sur cette discussion, mais, à lire ton intervention, j'ai envie de te poser une seule question:

    Pourquoi voudrais tu pouvoir utiliser une variable comme si elle était globale (que ce soit sous la forme d'un singleton ou non)

    Car, d'expérience:
    1. aucune variable ne doit effectivement être accessible depuis partout dans le code
    2. le simple fait de permettre à "n'importe quelle fonction" d'aller chipoter à une variable rend le code particulièrement difficile à débuger

    Le plus simple, si tu veux t'assurer qu'une variable ne sera créée qu'une fois, c'est encore de faire en sorte d'avoir cette garantie par la construction de ton code (en veillant à ce qu'il n'y ai qu'une seule déclaration de la variable du type indiqué) et de veiller à la transmettre sous la forme d'une référence (éventuellement constante) à "tout ce qui pourrait en avoir besoin"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre régulier
    Homme Profil pro
    .
    Inscrit en
    Octobre 2014
    Messages
    174
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : .
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2014
    Messages : 174
    Points : 90
    Points
    90
    Par défaut
    Salut Koala01,

    En réalité, l'objectif finale et de créer une classe dans une bibliothèque qui aurait pour rôle de charger une fois et une seule des ressources au début du programme, les stocker et les rendre disponibles un peut partout dans le code.
    Ici je charge des images, textures et autres..
    Je veux que ces ressources soient accessibles par certaine parties du programme sans avoir a recréer la classe et donc recharger ces ressources

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Hyssgrif Voir le message
    Salut Koala01,

    En réalité, l'objectif finale et de créer une classe dans une bibliothèque qui aurait pour rôle de charger une fois et une seule des ressources au début du programme, les stocker et les rendre disponibles un peut partout dans le code.
    Oui, c'est généralement ce que l'on attend de la part d'un singleton...

    Sauf que, si tu y regarde d'un peu plus près, il n'y a aucune ressource qui mérite réellement d'être rendue accessible depuis "n'importe où dans le programme":
    • Les sons ne sont utiles que pour le module sons
    • les textures / images/ données permettant de tracer différents éléments ne sont utiles que dans le module d'affichage
    • la connexion à un serveur externe n'est utile que dans le module ... net
    • et je pourrais continuer longtemps comme cela.

    Ici je charge des images, textures et autres..
    Je veux que ces ressources soient accessibles par certaine parties du programme sans avoir a recréer la classe et donc recharger ces ressources
    Tu n'as ni à les rendre disponibles depuis n'importe où (renseigne toi peut être sur le modèle MCV, ce genre de données faisant clairement partie de la vue ), ni à recréer l'instance de la classe qui les maintient en mémoire ou à les recharger : tu dois surtout déterminer le meilleur endroit pour créer une et une seule instance de cette classe et être en mesure de la transmettre à "qui en a besoin"

    Peut être devrais tu lire deux tickets de blogs d'emmanuel deloget :
    le premier est au sujet de la singletonite
    et le deuxième est au sujet de la gestion des gestionnaires

    Notes que, de manière générale, l'utilisation de termes comme "gestion", "gestionnaire", "management", et autre dans une étude de besoins s'avère souvent beaucoup trop vague que pour permettre de modéliser de telles notions "telles quelles" : la responsabilité de ce genre de notions est tellement mal définie que l'on finit par se retrouver avec quelque chose de monolithique, impossible à faire évoluer car s'occupant de beaucoup trop de choses
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Tu n'as ni à les rendre disponibles depuis n'importe où (renseigne toi peut être sur le modèle MCV, ce genre de données faisant clairement partie de la vue ), ni à recréer l'instance de la classe qui les maintient en mémoire ou à les recharger : tu dois surtout déterminer le meilleur endroit pour créer une et une seule instance de cette classe et être en mesure de la transmettre à "qui en a besoin"
    Le problème du singleton ce sont les responsabilités: qui peut le lire, qui peut l'écrire

    Un MVC n'est pas forcément utile, parce que tu peux encapsuler ton singleton dans ta classe principale [celle qui fait office de god class] et c'est elle qui va le créer, le détruire et le transmettre.


    Citation Envoyé par koala01 Voir le message
    Notes que, de manière générale, l'utilisation de termes comme "gestion", "gestionnaire", "management", et autre dans une étude de besoins s'avère souvent beaucoup trop vague que pour permettre de modéliser de telles notions "telles quelles" : la responsabilité de ce genre de notions est tellement mal définie que l'on finit par se retrouver avec quelque chose de monolithique, impossible à faire évoluer car s'occupant de beaucoup trop de choses
    Un manager ou gestionnaire peut être juste une classe déléguée vers des objets qu'il contient (c'est lui qui les crée et les détruit ce qui peut-être pratique pour avoir 1 [grosse] portion de ton code qui centralise cela)

    Et juste avec un paramètre tu peux choisir vers quel objet tu vas faire ta délégation

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par foetus Voir le message
    Le problème du singleton ce sont les responsabilités: qui peut le lire, qui peut l'écrire
    Tout à fait.

    Mais le problème est que tu arriveras très rapidement à vouloir y accéder -- ne serait-ce qu'en lecture -- à peu près partout. Et c'est logique : il est par nature prévu pour être accessible depuis n'importe où!

    Et bien sur, plus tu voudras l'utiliser n'importe où, plus tu auras tendance à lui donner des responsabilités qu'il n'a pas à avoir. Et là encore, c'est logique : il s'appellera très souvent XxxManager (*), et tu sera très souvent tenté de te dire que "mais en fait, mon XxxManager, il gère les Xxx... Et telle fonctionnalité fait partie de la gestion des Xxx..."

    Résultat des courses, tu vas te retrouver avec une classe qui fait énormément (beaucoup trop) de choses et qui est utilisées quasiment partout, ce qui va à l'encontre de deux des principaux principes SOLID : le SRP et l'OCP.

    Et, au final, tout ton projet dépendra d'une manière ou d'une autre de ton singleton, il sera quasiment impossible de faire évoluer ton projet sans passer par une modification de celui-ci.

    Sauf que, tu auras quasi systématiquement des modifications "mineures" au niveau de ton singleton qui "casse" au moins une chose (parfois même sans que tu ne t'en rende compte) au niveau de ton projet.

    Un MVC n'est pas forcément utile,
    C'est un modèle d'architecture qui présente l'énorme avantage qui tend à séparer clairement les différents éléments en fonction des différents modules et à réduire très fortement les dépendances entre les différents éléments. Et rien qu'en cela, c'est un modèle particulièrement intéressant à suivre

    parce que tu peux encapsuler ton singleton dans ta classe principale [celle qui fait office de god class] et c'est elle qui va le créer, le détruire et le transmettre.
    Quelle horreur!!!

    Je sais que ça date, mais tu devrais relire mes interventions au sujet des god_objects (note que j'ai même encore énormément évolué depuis et que je pourrais motiver mon malaise à ce sujet de manière bien plus claire maintenant )

    Un manager ou gestionnaire peut être juste une classe déléguée vers des objets qu'il contient (c'est lui qui les crée et les détruit ce qui peut-être pratique pour avoir 1 [grosse] portion de ton code qui centralise cela)

    Et juste avec un paramètre tu peux choisir vers quel objet tu vas faire ta délégation
    (*)
    He bien, selon toi, quelles fonctionnalités un RessourceManager (vu que c'est ce que Hyssgrif voudrait faire) devra-t-il fournir ?

    Commençons simple :
    1. les textures, c'est des ressources : il devra les gérer
    2. les sons, c'est des ressources : il devra aussi les gérer
    3. les descriptions d'objets devrant être affichés (les points qui les composent et les vertices qui relient ces point) sont aussi des ressources : il devra les gérer
    4. les entrées / sorties, c'est aussi des ressources : il devra les gérer
    5. (qui sait : ) une connexion à un serveur au travers d'internet, c'est aussi une ressource
    6. une base de donnée, pareil
    7. Et le pire de tout, c'est sans doute la configuration, parce que c'est une ressource qui permet de définir comment les autres ressources seront utilisée
    8. ... je pourrais surement trouver un tas d'autres ressources


    Et, comme tu n'a pas clairement désigné le type de ressource que ton manager devait gérer, à chaque nouvelle ressource que tu vas créer, tu vas avoir tendance à la faire gérer par... ton gestionnaire de ressources, même si le type de ressource que tu ajoute à ton manager n'est pas sensé être utilisé aux mêmes endroits que les ressources qu'il gère déjà.

    Tout cela aura pour résultat assez malsain de te conforter dans l'idée que "ton gestionnaire de ressources doit être accessible depuis n'importe où". Pourquoi malsain? me demandera tu ? Simplement parce que cela va créer un certain nombre de dépendances qui n'ont absolument aucune raison d'être : la partie qui s'occupe de l'affichage n'a absolument aucune raison d'avoir accès aux sons ou à la base de données qui seront rendus disponibles au travers de ton gestionnaire.

    Et toutes ces dépendances qui n'ont pas lieu d'être finiront forcément par transformer ton projet en un "tout monolithique" sous peine d'aller casser quelque chose à chaque fois que tu veux ajouter une fonctionnalité quelconque.

    Mais le pire, dans tout cela, c'est que je n'ai même pas encore abordé le problème de la signification même du terme manager! En effet, un manager, ca doit gérer quelque chose. Mais, si on prend l'exemple des textures, gérer les textures, cela revient à faire un certain nombre de choses à savoir:
    1. créer des textures (sans doute de différents types)
    2. charger des textures (sans doute de différents formats)
    3. maintenir les textures en mémoire et les rendre accessibles pour "qui en a besoin"


    Le (1) nous introduit la notion de factory; le (3) nous introduit celle d'un loader, le (3) nous introduit celle de "collection" (add, remove, getElement, ...) et, vu que tu n'as pas pris la peine de préciser exactement quelle responsabilité prenait ton gestionnaire (de textures), tu voudras "logiquement" lui donner ces trois responsabilités qui auraient du être distinctes.

    Si bien que là où tu n'aurais du pouvoir accéder qu'aux textures existantes, tu pourras aussi accéder à la création et au chargement de nouvelles textures. Or, si tu donne la possibilité à "quelqu'un" de profiter des fonctionnalités de création et de chargement de nouvelles textures, ce n'est qu'une question de temps avant que ce "quelqu'un" ne décide de les utiliser, même si il est dans une situation dans laquelle tout ce qu'il aurait du pouvoir faire c'est... accéder aux textures existantes.

    Et le résultat ne se fera pas attendre : tu te retrouveras très rapidement avec trois, cinq ou dix endroits où "quelqu'un" décide de charger ou de créer une texture.

    Et c'est là que les problèmes vont commencer, parce que, comme tu auras plusieurs endroits où "quelqu'un décide de charger ou de créer une texture", si tu as un problème de chargement ou de création de texture, tu es pour ainsi dire certain d'oublier l'un des endroits du code où le processus est lancé lorsque tu voudras corriger le problème.

    Et, bien sur, tout ce que j'ai dit pour les textures est tout aussi valable -- avec peut être quelques arrangements spécifiques -- pour tous les types de ressources que j'ai cité (et pour tous ceux que je n'ai pas cité )

    Le meilleur conseil à donner est donc : fais des petites classes aux responsabilités clairement établies (TextureFactory, TextureLoader, TextureHolder, SoundFactory, SoundLoader, SoundHolder, ...) qui pourront dés lors être utilisées sans arriver avec tout un cortège de fonctionnalités dont on n'a pas besoin et qui ne seront transmises (pour les XxxHolder, essentiellement) qu'aux éléments qui en ont vraiment besoin et, pour les autres, qui ne seront accessibles (et éventuellement, dont une instance ne pourra être créée) que pour/par les éléments qui prennent en charge un processus particulier au niveau de la gestion d'une ressource particulière.

    En "subdivisant" les responsabilités afférentes à tes différents manager (ou pire, afférentes à ton unique RessourceManger) en autant de classes prenant chacune une responsabilité spécifique, tu te rendras compte que:
    1. tu n'as absolument plus aucun besoin de disposer de "quelque chose qui soit accessible de partout"
    2. ton code sera globalement beaucoup plus simple
    3. ton code présentera globalement beaucoup moins de risques d'erreurs (logique : le risque d'erreur est au moins proportionnel au nombre d'instructions d'une fonction particulière)
    4. ton code sera beaucoup plus susceptible d'être testé intégralement (les tests unitaires, c'est un outil particulièrement nécessaire en développement )
    5. ton code sera beaucoup plus facile à débuger et à faire évoluer
    6. les dépendances entre les différentes fonctionnalités de ton projet seront beaucoup plus simples, et donc plus facile à prendre en compte


    Et tout cela, grace au simple respect de deux des principes SOLID : le SRP et l'OCP ... Avoue que c'est pas mal comme perspective, non
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Je ne suis pas d'accord

    Lorsque je parle de "god object" (peut-être à tord) c'est l'objet principal que certaines bibliothèques (surtout IHM comme Qt, VCL) ont besoin pour lancer l'application (et initialiser la fenêtre principale).
    Et je ne parle pas d'héritage, polymorphisme, héritage multiple, ou autre ... juste de l'utilisation de cette classe principale (*).

    Donc je trouve "étrange" que pour respecter les principes SOLID SRP OCP ou autres, on ne doit pas profiter de cette grosse classe (et de sa commodité).
    Surtout qu'un de ses rôles c'est l'initialisation au lancement (entre autres comme thread d'affichage ou les gros traits/ lignes de la logique IHM)
    Les managers sont d'ailleurs essentiellement initialisés au démarrage.

    Et lorsque tu parles de MVC, je voulais te faire remarquer que cette grosse classe peut faire office de contrôleur et ton manager de modèle.
    Après, pour différentes raisons (temps de démarrage, maintenance, évolution...), tu peux le faire évoluer en un vrai MVC.


    Citation Envoyé par koala01 Voir le message
    Et, au final, tout ton projet dépendra d'une manière ou d'une autre de ton singleton, il sera quasiment impossible de faire évoluer ton projet sans passer par une modification de celui-ci.

    Sauf que, tu auras quasi systématiquement des modifications "mineures" au niveau de ton singleton qui "casse" au moins une chose (parfois même sans que tu ne t'en rende compte) au niveau de ton projet.
    J'ai dû mal à voir un projet/ application avec lequel/ laquelle toutes les classes ont très peu de dépendances
    Déjà la classe principale (*) est un contre-exemple.

    Ou alors un petit projet, une petite application.

    Parce que c'est bien joli d'avoir une armée de classes à 1 responsabilité, de pouvoir les tester individuellement (**), etc..., mais après il faut mettre en place tout le ciment pour créer/ détruire et aussi passer le bon objet. Sans parler de ton projet qui explose en terme de classes/ fichiers.
    Ton exemple de classes: TextureFactory, TextureLoader, TextureHolder, SoundFactory, SoundLoader, SoundHolder, ... cela fait un peu peur

    Une mise en situation: tu codes un jeu et tu dois prendre en compte 3 types de textures (png, DXT je-ne-sais-pas-quoi, et autre chose) et 2 types de sons.

    Au lieu d'avoir 5 grosses classes + 1 manager "classe déléguée" (mais il y a sûrement d'autres façons de coder) (et je signale au passage que si tu cherches un algo par rapport au mp3 ou au png, tu sais exactement où il est) tu vas avoir (3xX + 2xY) classes.
    Sans parler du fait que rien pour gérer tout cela tu vas mettre en place de l'héritage (certes simpliste), mais un héritage quand même. Donc (3xX + X + 2xY + Y) classes

    Je prévois déjà que tu vas me répondre que ton IDE c'est le plus puissant de la terre (VIM, Visual, ...) que tu t'en fiches tu gères X projets en même temps (donc tu n'es pas à quelques classes en plus) et que je n'ai jamais codé sur/ maintenu un gros projet monolithique.

    Et je peux rajouter que je code que des applications pas des bibliothèques mais avec de la conception pour reprendre et réutiliser "une colonne vertébrale".

    Citation Envoyé par koala01 Voir le message
    1. les textures, c'est des ressources : il devra les gérer
    2. les sons, c'est des ressources : il devra aussi les gérer
    3. les descriptions d'objets devrant être affichés (les points qui les composent et les vertices qui relient ces point) sont aussi des ressources : il devra les gérer
    4. les entrées / sorties, c'est aussi des ressources : il devra les gérer
    5. (qui sait : ) une connexion à un serveur au travers d'internet, c'est aussi une ressource
    6. une base de donnée, pareil
    7. Et le pire de tout, c'est sans doute la configuration, parce que c'est une ressource qui permet de définir comment les autres ressources seront utilisée
    8. ... je pourrais surement trouver un tas d'autres ressources
    Évidement si tu ne te contrains pas par toi-même, tu vas avoir une armée de managers

    > les descriptions d'objets devrant être affichés (les points qui les composent et les vertices qui relient ces point) sont aussi des ressources :
    Pourquoi des ressources? Ce sont en règle générale des classes avec une logique ultra-ultra réduite. Tellement réduite que tu peux faire une classe=une entête seulement.

    Par exemple: un Point 2D: x, y - un élément dans une liste plate (listview par exemple): texte ID - un utilisateur: ID, nom, prénom, société.

    > une base de donnée, pareil
    C'est ce que j'appelle des "App Datas"

    Pour moi, il y a 2 types de "App Datas"
    1. Beaucoup d'attributs, quasi aucune logique. Un "gros panier" (très souvent en lecture seule) qu'on passe d'un objet à un autre.
    2. Très peu d'attributs, mais beaucoup de logique. Par exemple: une base de donnée. Tu vas avoir 2-3 "handles" et à côté toutes tes requêtes SQL (et éventuellement des procédures stockées et des triggers).


    Et si j'ai un gros fichier .cpp, en C/ C++ on peut casser ce gros fichier en plusieurs (il faut juste un include de ton fichier .h dans chacun) afin de faire une répartition logique de ses méthodes.

    > Et le pire de tout, c'est sans doute la configuration
    Pour moi, la configuration ce sont 2 méthodes load/ save + une structure
    Même une configuration comme Apache je ne pense pas que ce soit différent.

    Et comme tu ne sauvegardes pas ta configuration souvent, ta grosse classe(*) peut la gérer toute seule.
    Surtout que la configuration est chargée au lancement.
    Et au passage, tu n'as pas de Configuration Manager en mémoire pour rien.


    Citation Envoyé par koala01 Voir le message
    Et le résultat ne se fera pas attendre : tu te retrouveras très rapidement avec trois, cinq ou dix endroits où "quelqu'un" décide de charger ou de créer une texture.
    C'est sûr que si tu fais un manager sans réfléchir cela va être compliqué par la suite

    Pour moi un manager c'est une "classe déléguée" vers des objets concrets qu'il contient. Une sorte de proxy, interface, ou patron de conception du même style.

    Mais, ce que je fais, (<- Un gros mais), ton manager expose que des méthodes classiques et/ ou "en lecture seule".

    Pour un Texture Manager: get_texture/ list_textures.
    Pour un Sound Manager: get_sound/ list_sounds.

    Ainsi, tu peux facilement échanger les classes concrètes: MP3_Sound_Manager, WAV_Sound_Manager.

    Et à côté de cela, prévoir un système via ton Manager (***) pour récupérer un objet concret et avoir une interface spécifique étendue:
    MP3_Sound_Manager::create_sound(), JPG_Texture_Manager::set_compression_level(), ...

    D'ailleurs, je ne pense pas que ces méthodes spécifiques soient utiles partout . Juste à des endroits précis.

    Toujours le même principe : cela ne me dérange pas que ma classe Manager soit utilisée à pleins d'endroits.
    Parce que 0) c'est un peu son rôle (comme un frigo dans une cuisine) 1) j'ai contrains un grand nombre de ses méthodes en lecture seule 2) effet "bottle neck" avec un point d'arrêt dans le manager 3) avec une recherche, je trouve toutes les occurrences


    ** -> si c'est possible par exemple un bouton qui s'adapte à la taille de son texte, ou un algo de rendu.
    *** -> par exemple: private + friend

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par foetus Voir le message
    Je ne suis pas d'accord

    Lorsque je parle de "god object" (peut-être à tord) c'est l'objet principal que certaines bibliothèques (surtout IHM comme Qt, VCL) ont besoin pour lancer l'application (et initialiser la fenêtre principale).
    Et je ne parle pas d'héritage, polymorphisme, héritage multiple, ou autre ... juste de l'utilisation de cette classe principale (*).
    Ah, ben oui, tu as effectivement une classe (QApplication, dans le cas de Qt) qui va mettre tout le système en branle et s'assurer que tout sera correctement initialisé. Ce n'est pas une raison (et c'est l'un des reproche que je fais à Qt) pour connaitre cette classe pour pouvoir accéder aux différents services quelle regroupe. D'autant plus que les services en question sont TOUS modélisés sous la forme d'une classe spécifique.

    Ceci dit, le domaine de l'IHM est -- justement -- le contre exemple flagrant de ce qu'il faut faire à bien des égards
    Donc je trouve "étrange" que pour respecter les principes SOLID SRP OCP ou autres, on ne doit pas profiter de cette grosse classe (et de sa commodité).
    Surtout qu'un de ses rôles c'est l'initialisation au lancement (entre autres comme thread d'affichage ou les gros traits/ lignes de la logique IHM)
    Oui, bien sur : il est important de veiller à ce que tout ce qui doit être initialisé pour fournir les services que l'on attend de la part d'une IHM soit initialisé de manière simple (ex, comme c'est le cas de Qt, en ayant une classe spécifique dont l'instanciation s'occupera de créer tous les éléments nécessaires pour rendre ces services)
    Les managers sont d'ailleurs essentiellement initialisés au démarrage.
    (je passe sur le problème qu'il peut y avoir à parler de "managers" ou de "gestionnaires"... je reviendrai dessus à la fin de mon intervention )
    Oui, et alors Qu'est ce qui t'empêche d'avoir une classe proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class MaClasseEntreeApplication{
    /* ... */
    private:
        /* juste au cas où on voudrait l'instancier deux fois */
        static bool alreadyCreated_;
        ThreadStack threads_;
        EventHandlerCollection events_;
        /* ... */
    };
    /* pour ne pas devoir passer par MaClasseEntreeApplication */
    EventHanderlCollection & events(){
        /* peu importe comment on le récupère */
    }
    ThreadStack threads(){
        /* peu importe comment on le récupère */
    }
    .... someStuffWeWantToGet() {
        /* ... */
    }
    La loi de Déméter dit que, si un objet de type A manipule en interne un objet de type B, l'utilisateur du type A ne doit pas avoir connaissance du type B pour manipuler son objet de type A.

    Mais il ne faut pas non (et encore moins) plus obliger l'utilisateur du type B à connaitre le type A pour pouvoir accéder à son type B.

    La plupart des bibliothèques d'IHM sont apparues à une époque où
    1. la philosophie était proche du "tout objet" (comprend : fonctions membres uniquement), en ignorant volontairement les possibilités multi paradigme du C++
    2. l'approche du paradigme orienté objet était encore bien plus orientée sur les données manipulées que sur les services rendus par les différentes fonctionnalités (il suffit de voir le nombre de mutateurs pour s'en convaincre)

    Alors, bien sur, dans un tel contexte, il devient sans doute impossible de se passer de la notion de singleton. Mais, si tu accepte l'idée de créer des fonctions libres et que tu commences réellement à penser en termes de services et non en termes de données manipulées, tu te rendras compte qu'il n'y a rien qui soit fournit par ton singleton qui doive effectivement être disponible strictement partout et que, si tu as besoin de certaines fonctionnalités proposées par ton singleton à plusieurs endroits, tu n'as absolument aucun besoin de pouvoir accéder à l'ensemble de ces fonctionnalités.

    Dés lors, si tu sépare l'ensemble des fonctionnalités proposées par ton singleton en autant de fonctionnalités distinctes et indépendantes, tu gagne la liberté de ne fournir que ce dont tu as réellement besoin à chaque moment et, surtout, tu gagne à ne pas être tenté de rajouter une dépendance dont tu aurais pu te passer.
    Et lorsque tu parles de MVC, je voulais te faire remarquer que cette grosse classe peut faire office de contrôleur et ton manager de modèle.
    Après, pour différentes raisons (temps de démarrage, maintenance, évolution...), tu peux le faire évoluer en un vrai MVC.
    La question que je te poserai à ce sujet est : pourquoi attendre pour décider d'utiliser quelque chose dont tu as la garantie que tu devra de toutes manières y avoir recours

    Il sera beaucoup plus facile pour toi de mettre directement un MVC correct en route que de commencer en regroupant les fonctionnalités propres au(x) contrôleur(s) et celles propres au(x différents) moèle(s) et de devoir séparer le tout "après coup" parce que tu te rend compte que cela devient ingérable
    J'ai dû mal à voir un projet/ application avec lequel/ laquelle toutes les classes ont très peu de dépendances
    Déjà la classe principale (*) est un contre-exemple.

    Ou alors un petit projet, une petite application.
    Tu n'as alors jamais vu les projets sur lesquels j'ai travaillé...

    Certains étaient de très gros projets, et on limitait pourtant les dépendances au stricte minimum. Et il y a parfaitement moyen de le faire
    Parce que c'est bien joli d'avoir une armée de classes à 1 responsabilité, de pouvoir les tester individuellement (**), etc..., mais après il faut mettre en place tout le ciment pour créer/ détruire et aussi passer le bon objet. Sans parler de ton projet qui explose en terme de classes/ fichiers.
    Le ciment à mettre en place pour gérer cette armada de petite classe est beaucoup plus simple que celui nécessaire pour éviter de faire tomber tout un tas de classes monolithiques, je peux te l'assurer
    Ton exemple de classes: TextureFactory, TextureLoader, TextureHolder, SoundFactory, SoundLoader, SoundHolder, ... cela fait un peu peur
    Pourquoi est ce qu'il te fait peur
    Une mise en situation: tu codes un jeu et tu dois prendre en compte 3 types de textures (png, DXT je-ne-sais-pas-quoi, et autre chose) et 2 types de sons.

    Au lieu d'avoir 5 grosses classes + 1 manager "classe déléguée" (mais il y a sûrement d'autres façons de coder) (et je signale au passage que si tu cherches un algo par rapport au mp3 ou au png, tu sais exactement où il est) tu vas avoir (3xX + 2xY) classes.

    Sans parler du fait que rien pour gérer tout cela tu vas mettre en place de l'héritage (certes simpliste), mais un héritage quand même. Donc (3xX + X + 2xY + Y) classes
    J'aurais surement un nombre de classes plus grand que 1 ou 2, ca je te l'accorde mais :

    1 - Très peu d'héritage:
    1. peut être pour faire la distinction entre les textures "données" (issues de formats comme png ou jpeg) est les textures "fonctionnelles",
    2. peut être pour faire pareil au niveau de Sound (mais aucun lien entre Sound et Texture);
    3. Peut-être, au niveau des loader permettant de charger différents formats de textures ou différents formats de sons (mais, encore une fois, sans liens entre les SoundLoader et les TextureLoader, autres que leur interface, peut être)

    2- J'aurais, effectivement, une TextureFactory et une SoundFactory qui me permettraient respectivement de "centraliser" la connaissances des différents types dérivés, ce qui me permettrait de n'avoir pas besoin de savoir autre chose que le fait que je manipule une texture ou un son partout ailleurs
    3- j'aurais effectivement un TextureHolder et un SoundHolder, qui se contenteraient de maintenir les textures (respectivement les sons) en mémoire "tant qu'ils sont utilisés"
    Je prévois déjà que tu vas me répondre que ton IDE c'est le plus puissant de la terre (VIM, Visual, ...)
    A vrai dire, à titre perso, je code généralement avec un truc aussi simple que gedit (notepad++) et en utilisant les autotools sous linux... On peut trouver assez facilement des solutions "plus puissantes" pour faire le travail

    Et pourtant, le nombre de fichiers / de classes ne me fait absolument pas peur . Par contre, ce qui m'énerve à chaque fois, c'est de voir une série de tests unitaires planter parce que j'ai eu "le malheur" de vouloir intégrer une évolution à mon projet
    que tu t'en fiches tu gères X projets en même temps (donc tu n'es pas à quelques classes en plus)
    J'ai effectivement, plusieurs projets perso en cours...

    Mais ce n'est pas pour cela que je ne suis pas à "quelques classes de plus"... Si je ne suis pas à "quelque classes de plus", c'est parce que j'ai eu très largement l'occasion de me rendre compte de tous le bénéfice que l'on peut tirer à effectivement séparer clairement les différentes fonctionnalités
    et que je n'ai jamais codé sur/ maintenu un gros projet monolithique.
    Je ne te connais pas assez pour dire cela
    Et je peux rajouter que je code que des applications pas des bibliothèques mais avec de la conception pour reprendre et réutiliser "une colonne vertébrale".
    Et, si je ne veux récupérer qu'une vertèbre je fais comment je prend toute la colonne vertébrale, ou j'arrive à ne prendre que L4 sans trop me casser la tête
    Évidement si tu ne te contrains pas par toi-même, tu vas avoir une armée de managers
    On arrive bientot au bout... les explications vont venir
    > les descriptions d'objets devrant être affichés (les points qui les composent et les vertices qui relient ces point) sont aussi des ressources :
    Pourquoi des ressources? Ce sont en règle générale des classes avec une logique ultra-ultra réduite. Tellement réduite que tu peux faire une classe=une entête seulement.
    Je voulais parler des données destinées à être envoyées à OpenGL que tu récupères en lisant un fichier .obj ou 3ds
    Par exemple: un Point 2D: x, y - un élément dans une liste plate (listview par exemple): texte ID - un utilisateur: ID, nom, prénom, société.

    > une base de donnée, pareil
    C'est ce que j'appelle des "App Datas"

    Pour moi, il y a 2 types de "App Datas"
    1. Beaucoup d'attributs, quasi aucune logique. Un "gros panier" (très souvent en lecture seule) qu'on passe d'un objet à un autre.
    2. Très peu d'attributs, mais beaucoup de logique. Par exemple: une base de donnée. Tu vas avoir 2-3 "handles" et à côté toutes tes requêtes SQL (et éventuellement des procédures stockées et des triggers).
    Tout dépend de la définition que tu fais du terme "ressources".

    Le vrai problème, c'est que même si tu te limite aux seules "ressources informatiques" (en générale), la définition de ce terme est proche (selon wikipedia) de
    Citation Envoyé par wikipedia
    En informatique, les ressources sont des composants, matériels ou logiciels, connectés à un ordinateur. Tout composant de système interne est une ressource. Les ressources d'un système virtuel incluent les fichiers, les connexions au réseau, et les zones de mémoire.
    En cela, ce que tu appelle App Datas ne sont rien d'autre que... des ressources
    > Et le pire de tout, c'est sans doute la configuration
    Pour moi, la configuration ce sont 2 méthodes load/ save + une structure
    Même une configuration comme Apache je ne pense pas que ce soit différent.
    Non, les fonctions load et save ne sont que les parties visibles de l'iceberg...

    La partie non visible, c'est que, même s'il ne s'agit que d'une structure "POD", c'est bel et bien une ressource (quelque chose qui utilise de la mémoire) et qui utilisé quasiment partout dans le code, parce que l'on y mélange allègrement les données de configuration de tout et de n'importe quoi (ex : taille et résolution d'affichage, volumes sonores divers, adresses des serveurs à contacter, nom d'utilisateur, ...)
    Et comme tu ne sauvegardes pas ta configuration souvent, ta grosse classe(*) peut la gérer toute seule.
    Je ne dis pas que la classe qui sert de point d'entrée de l'application ne doit pas gérer ta configuration d'une manière ou d'une autre; je dis:
    • que tu ne devrais pas avoir besoin de passer par ta classe "point d'entrée de l'applicaiton" pour accéder à la configuration
    • que tu n'a jamais besoin de toutes les données que la configuration met à ta disposition :
      • si tu est dans un contexte d'affichage, c'est la taille et la résolution de l'écran qui t'intéressent;
      • si tu est dans un contexte de requête SQL / connexion à un serveur, ce sont les adresses du serveur, le nom d'utilisateur,... qui t'intéressent;
      • si tu es dans un contexte sonore, ce sont les volumes sonores qui t'intéressent
      • ...

    Surtout que la configuration est chargée au lancement.
    Oui, elle sera sans doute chargée au lancement de l'application et sauvegardée (si modifiée) à la fermeture de l'application.
    Et au passage, tu n'as pas de Configuration Manager en mémoire pour rien.
    Ben, je dis justement qu'on n'en a pas besoin... En tout sous la forme d'un "gestionnaire de configuration", et surtout pas si cela sous entend de maintenir la configuration des différents "modules" de notre application "mélangés" au sein d'une seule structure.

    Je suis tout à fait d'accord pour dire qu'il doit "forcément" y avoir un endroit où l'on regroupera toutes les configurations de tous les modules (ne serait-ce que parce que la configuration de tous les modules peut se retrouver dans un seul et unique fichier de configuration).

    Mais on n'a absolument aucun besoin de savoir comment sont traités les sons quand on essaye de se connecter à un serveur distant!

    [/QUOTE]
    C'est sûr que si tu fais un manager sans réfléchir cela va être compliqué par la suite

    Pour moi un manager c'est une "classe déléguée" vers des objets concrets qu'il contient. Une sorte de proxy, interface, ou patron de conception du même style.

    Mais, ce que je fais, (<- Un gros mais), ton manager expose que des méthodes classiques et/ ou "en lecture seule".

    Pour un Texture Manager: get_texture/ list_textures.
    Pour un Sound Manager: get_sound/ list_sounds.

    Ainsi, tu peux facilement échanger les classes concrètes: MP3_Sound_Manager, WAV_Sound_Manager.
    [/QUOTE]Que le son soit au format mp3, au format wav ou au format whatTheFuck, tu t'en fous royalement... tout ce qui t'importe, c'est de pouvoir le jouer

    Et c'est justement parce que tu espère pouvoir profiter des comportements polymorphes pour tes sons ou tes textures (text.drawIt(context); pour une texture; sound.playIt(context); pour un son) qu'il est important de limiter la tentation de l'utilisateur de "celui qui récupère une texture / un son" de chercher à savoir "quel en est le type réel".

    Et c'est pour cela qu'il est important de séparer clairement les différentes responsabilités (qui crée la texture ou le son, qui la/le charge, qui la/le maintient en mémoire), de manière à ce que l'utilisateur puisse recevoir une "référence" (qui sera en réalité un pointeur ou une référence C++) sur "une texture" ou sur "un son" et pour qu'il puisse savoir qu'il "doit faire avec", sans essayer de récupérer le "type réel" de sa texture ou de son son.
    Et à côté de cela, prévoir un système via ton Manager (***) pour récupérer un objet concret et avoir une interface spécifique étendue:
    MP3_Sound_Manager::create_sound(), JPG_Texture_Manager::set_compression_level(), ...
    Mais ca, c'est pas le gestionnaire qui doit s'en occuper...
    la création d'un son est un mécanisme dont l'utilisateur n'a absolument rien à foutre et qui devrait être délégué à une fabrique (qui se décharge d'une partie du travail sur différents Loaders) et réglage du niveau de compression JPEG, ca se gère exclusivement au niveau de la sérialisation (chargement /sauvegarde) du fichier.

    Alors, que tu aies une fonction add(filename) qui passe par la fabrique pour ajouter une texture ou un son (selon ce que tu manipules) est tout à fait cohérent, mais l'utilisateur de ce qui devient un TextureHolder ou un SoundHolder (une classe qui se contente de fournir les services relatifs au maintient des sons/des textures en mémoire) n'a absolument pas besoin de savoir comment le son / la texture ajoutée a été créée (et au paravant chargée).

    D'ailleurs, je ne pense pas que ces méthodes spécifiques soient utiles partout . Juste à des endroits précis.
    Raison de plus pour ne pas les rendre accessibles partout parce que disponibles dans l'interface d'une classe qui, par nature, risque de se retrouver "n'importe où"...
    Toujours le même principe : cela ne me dérange pas que ma classe Manager soit utilisée à pleins d'endroits.
    Parce que 0) c'est un peu son rôle (comme un frigo dans une cuisine) 1) j'ai contrains un grand nombre de ses méthodes en lecture seule 2) effet "bottle neck" avec un point d'arrêt dans le manager 3) avec une recherche, je trouve toutes les occurrences
    Tu obtiens exactement le même résultat mais en mieux en séparant ton manager "monolithique" en différentes classes aux responsabilités restreintes car:
    1. C'est le role d'un TextureHolder de maintenir les textures en mémoire tant que tu en as besoin (mais c'est aussi celui d'un SoundHolder, sauf que tu n'auras que des sons ou des textures , un peu comme un frigo dans une cuisine
    2. tu mes un points d'arrêt sur un TextureHolder et tu es sur que chaque fois que tu passe sur ce point d'arrêt, c'est parce que tu manipule une texture. Même chose pour les sons et ton SoundHolder, et pour n'importe quel autre type de ressource
    3. la recherche de ton instance de TextureHolder ou de ton instance de SoundHolder est beaucoup plus précise que celle de ton Manager car tu n'en a rien à foutre des circonstances dans lesquelles tu manipules un son si tu cherche celles où tu manipule une texture (et vice versa)


    Désolé, pour finir, je ferai mon spitch sur les "manager" demain
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] pattern singleton
    Par SirDarken dans le forum Débuter avec Java
    Réponses: 22
    Dernier message: 11/12/2004, 01h55
  2. Mutiple row in singleton select ????? [Important, merci]
    Par SkyDev dans le forum Bases de données
    Réponses: 6
    Dernier message: 20/04/2004, 14h02
  3. [debutant]Singleton
    Par bafman dans le forum Langage SQL
    Réponses: 6
    Dernier message: 13/01/2004, 15h41

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