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 :

Problème de conception : chargement de config


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut Problème de conception : chargement de config
    Bonjour,

    Je cherche à charger des paramètres de configuration dans mon application.

    1) Je vais donc avoir une classe de départ Config, pour laquelle je n'ai pas encore choisi la conception exacte (singleton/static load). Y a-t-il une préférence parmi ces deux options ?

    2) Mon vrai problème arrive ensuite, lorsque je veux "propager" mes paramètres aux différentes classes.

    a) Ma première idée était de venir simplement chercher depuis ma classe X le paramètre dont j'ai besoin via Config::M_param, avec M_param une variable statique de ma classe Config.
    Inconvénient : mes classes dépendent directement de la Config.

    b) Une autre idée était donc de commencer à initialiser dans chaque classe des variables statiques représentant mes paramètres et de venir ensuite appeler une méthode de chargement load pour éventuellement charger les valeurs d'un fichier de config.
    Problème : il me faut une méthode de base héritée par mes classes pour le chargement. Or, je souhaite garder mes variables en statique car je trouve ça plus logique d'associer les paramètres à une classe plutôt qu'à une instance. Seulement, si je veux garder tout le chargement de la Config en statique, il m'est impossible d'avoir une méthode de chargement héritée par mes classes. Avez-vous une idée ?

    Pour information, j'envisage ensuite d'utiliser le modèle Observer entre la Config et toutes mes classes pour le chargement.

    Merci à vous

  2. #2
    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,

    La première chose à faire, c'est de veiller à parfaitement séparer les différents modules et responsabilités.

    Non seulement au niveau de la gestion des options de configuration, mais aussi -- et surtout -- au niveau des fonctionnalités proposées par ton projet.

    En effet, si ton application travaille en réseau, l'affichage n'aura besoin que des options "cosmétiques" permettant de définir les couleurs, les polices de caractères à utiliser ou la taille de l'affichage. Elle n'aura absolument que faire des options spécifiques au réseau (sauf, évidemment, pour l'éventuel onglet qui doit te permettre de les modifier )

    Chaque "module" de ton application -- base métier, sauvegarde/chargement, réseau, affichage, son, ... -- devrait pouvoir travailler de manière strictement indépendante des autres (à l'exception de quelques "point d'accès" car il faudra bien que ces modules communiquent avec les autres ) et ne devrait donc avoir accès qu'aux options de configuration qui lui sont propres.

    Et les différentes parties d'un module n'ont pas forcément besoin de disposer de toutes les options qui concernent ce module.

    Le module réseau, par exemple, sera composé d'une classe qui aura pour but de créer et de maintenir la connexion active (ConnexionHolder ).

    Cette classe aura besoin des options relatives à cette tâche, à savoir : le nom du serveur à contacter, le port, le protocole à utiliser, le nom d'utilisateur, son mot de passe, et autres auxquelles ne je pense pas forcément.

    Mais on pourrait envisager d'indiquer la méthode de signature, de compression ou simplement d'encodage du contenu émis.

    Ces informations ne sont sans doute absolument pas nécessaire à la classe ConnexionHolder mais seront par contre indispensable à la classe qui s'occupe de la transmission en elle-même. Et cette dernière n'aura absolument pas à s'inquiéter des options relatives à la mise en place et au maintient de la connexion.

    Par contre, il est très vraisemblable (en tout cas, je t'incite à le faire) que tu mettras en place un système fort proche du patron de conception Façade pour permettre aux autres modules de communiquer avec ton module "réseau".

    Cette façade, qui pourrait tout aussi bien être une classe, serait le candidat idéal à qui fournir l'ensemble des options propres au réseau, vu que c'est au travers de cette façade que toutes les fonctionnalités du réseau seront utilisées. Elle serait donc particulièrement bien placée pour transmettre l'option utile à "qui de droit"

    Et bien sûr, tu travaillerais de manière strictement similaire pour tous les modules

    Au final, tu aurais une dernière classe, mettons Application, qui mettrait en présence les différents modules qu'elle utilise, éventuellement en tenant compte d'options qui la concernent directement (si tu as une option --nosound, c'est sans doute pour indiquer à l'application qu'elle ne doit pas activer le système de gestion du son ) et qui "dispatcherait" les options adéquates vers les modules qui en ont besoin.

    Je suis globalement contre le patron de conception singleton parce que j'estime (et je ne suis pas le seul ) qu'il s'agit d'un "anti pattern" dans le sens où le meilleur moyen pour s'assurer qu'une donnée ne sera pas dupliquée, c'est encore de veiller à n'en créer qu'une seule.

    En plus, le patron de conception Singleton utilise forcément une variable statique pour fonctionner.

    Or, une variable statique n'est jamais qu'une variable globale "Facon du chef, enrobée d'accessibilité sur lit de mystère, avec sa sauce OO"

    Au final, je dirais : pas de variables statiques, mais des variables "tout à fait classiques" qui seront, selon le cas, transmises comme argument à une fonction ou au constructeur (sous la forme d'une référence non constante, si besoin) des objets qui en ont réellement 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

  3. #3
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Perso, je suis pas trop d'accord, dans tout mes projets (et projets professionnel) les classe de configuration sont des singleton renvoyant les différentes variables.

    Exemple:
    Mon fichier de configuration est un xml classique:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <configuration>
      <port>4242</port>
      <ip>127.0.0.1</ip>
    </configuration>
    Ensuite ma classe de configuration va aller parser ce fichier et stocker les information sous forme de map:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::map<std::string, std::string> info;
    Pour y accéder j'ai juste besoin d'appelé une des fonction pour récupérer une variable:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int getInt(std::string cle)
    {
       return (toInt(info[cle]));
    }
    std::string getString(std::string cle)
    {
      return (info[cle]);
    }
    (Ce n'est qu'une ébauche de ce que j'ai réellement, mais c'est pour donner une idée).

    Ce système permet de rajouté des variable dans le fichiers de configuration sans avoir à recodé une partie du programme.

    C'est beaucoup plus dynamique que d'avoir un membre d'une classe qui stock un paramètre. Imagine que tu doives rajouter x paramètre pour plusieurs classes, il faudra alors que tu re-développe les constructeurs de tes classes.

    Imagine une classe ayant besoin de 10 paramètre, tu vas pas appelé un constructeur avec 10 variable quand même?
    Imagine que ce constructeur soit appelé 50 fois dans ton code, tu vas aller modifié 50 fois ces lignes?

    C'est pourquoi je pense qu'il est nettement mieux de passer par un singleton pour la configuration, ce n'est pas une partie très sensible d'une application donc on peut se le permettre.
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    Bonjour et merci à tous les deux pour vos suggestions .
    C'est intéressant d'avoir ici deux points de vue!

    koala01 :
    Je suis globalement contre le patron de conception singleton parce que j'estime (et je ne suis pas le seul ) qu'il s'agit d'un "anti pattern" dans le sens où le meilleur moyen pour s'assurer qu'une donnée ne sera pas dupliquée, c'est encore de veiller à n'en créer qu'une seule.
    Ok mais charge au(x) développeur(s) de faire attention à ne pas instancier un nouvel objet qui ferait doublon alors, c'est ça? Pourquoi rester trop permissif au niveau de la conception si au final on veut qu'une seule et unique instance ?

    Or, une variable statique n'est jamais qu'une variable globale "Facon du chef, enrobée d'accessibilité sur lit de mystère, avec sa sauce OO"
    En fait, j'avais envisagé de mettre mes paramètres de configuration par défaut en variable statique privée, ce qui réduit quand même la visibilité à la classe considérée, je trouve donc ça pas trop mal a priori.

    Sinon, la Config serait aussi pour toi un objet instanciable classique ?

    Au final, je dirais : pas de variables statiques, mais des variables "tout à fait classiques" qui seront, selon le cas, transmises comme argument à une fonction ou au constructeur (sous la forme d'une référence non constante, si besoin) des objets qui en ont réellement besoin
    Skeud :
    Imagine que tu doives rajouter x paramètre pour plusieurs classes, il faudra alors que tu re-développe les constructeurs de tes classes
    A moins peut être de réaliser quelque chose d'assez générique en passant par exemple en constructeur une structure qui stocke les paramètres de configuration du module donné ? Enfin après, même si la signature des constructeurs restent inchangées, il faudra quand même définir les nouveaux membres pour stocker les nouveaux paramètres donc non c'est pas mieux ^^.

  5. #5
    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 skeud Voir le message
    Perso, je suis pas trop d'accord, dans tout mes projets (et projets professionnel) les classe de configuration sont des singleton renvoyant les différentes variables.

    Pour y accéder j'ai juste besoin d'appelé une des fonction pour récupérer une variable:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int getInt(std::string cle)
    {
       return (toInt(info[cle]));
    }
    std::string getString(std::string cle)
    {
      return (info[cle]);
    }
    J’ai pas mal utilisé ça, mais je trouve qu’il y a deux défauts principaux à cette approche :
    - la description du fichier de configuration est éparpillée à plein d’endroits (en fait, partout où on utilise des paramètres de l’application), ce qui fait qu’il est difficile de lister tous les paramètres possibles de l’application.
    - l’interface incite à utiliser directement le paramètre de configuration partout où on en a besoin en utilisant Config::get(XXX), où XXX est une chaîne de caractères, ce qui peut amener des bugs idiots dus à des fautes de frappe (et si c’est à un endroit du code où on ne passe pas souvent, ça peut être plus compliqué qu’on ne croit à détecter), ou compliquer le refactoring en cas de changement du nom du paramètre.

    Cela dit, ça fonctionne et c’est simple à utiliser. Je recommande quand même du coup de s’imposer les limites suivantes :
    - un paramètre de configuration en doit être lu qu’une seule fois, dans une fonction d’initialisation de l’objet dédiée
    - la map des paramètres doit être hiérarchisée, de sorte qu’un module ne connaisse que ses propres paramètres et pas ceux des autres modules. Ça protège aussi des conflits de nom (par exemple, un programme qui accèderait à la fois à une bdd et à un service web pourrait avoir deux fois le paramètre username, mais pour deux contextes différents).

    Citation:
    Imagine que tu doives rajouter x paramètre pour plusieurs classes, il faudra alors que tu re-développe les constructeurs de tes classes
    Effectivement, un gros intérêt pour une bibliothèque est de pouvoir rajouter un paramètre tout en gardant la compatibilité binaire.

  6. #6
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    - l’interface incite à utiliser directement le paramètre de configuration partout où on en a besoin en utilisant Config::get(XXX), où XXX est une chaîne de caractères, ce qui peut amener des bugs idiots dus à des fautes de frappe (et si c’est à un endroit du code où on ne passe pas souvent, ça peut être plus compliqué qu’on ne croit à détecter), ou compliquer le refactoring en cas de changement du nom du paramètre.
    C'est pourquoi j'utilise en général dans chacun de mes header de classe ou directement dans la configuration un enum ou des constantes définissant le nom des variables du fichier de configuration.

    Une autre implémentation possible est d'avoir un objet configuration par module qui va chercher et charger exclusivement les paramètres qui concerne le module:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <configuration>
      <reseau>
        <port>4242</port>
        <ip>127.0.0.1</ip>
      </reseau>
      <log>
        <fichier>toto.log</fichier>
        <level>DEBUG</level>
      </log>
      ...
    </configuration>
    Voir aussi un fichier de configuration par module.

    Et le constructeur de la classe configuration prend en paramètre le nom du module.
    Cela permet d'avoir dans chaque module une classe de configuration qui contient que les paramètre du module, mais en contrepartis il faut se trimballé l'instance de la classe de configuration un peu partout car on y accède pas en singleton.

    On peut aussi bien configurer la classe singleton qui stock la configuration pour hiérarchisé les information:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    std::map<std::string, std::map<std::string, std::string>> info;
     
    getString(std::string module, std::string cle)
    {
      return(info[module][cle]);
    }
    L'énorme avantage que je vois c'est la modularité de ce fonctionnement, le but étant d'avoir un maximum d'information en dehors du code pour pouvoir changer le comportement de l'application sans recompiler.

    Bien sur, comme toute chose, il faut l'utilisé avec paricimonie pour ne pas être dans la sur-configuration.
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    Vos méthodes me semblent plutôt bonnes mais ce qui me gène encore, c'est le fait d'associer les paramètres à un objet lors de son initialisation. C'est pourquoi je préfèrerais garder mes paramètres en variables statiques privées pour chacun de mes modules.

    Voici en brouillon une solution en Qt pour laquelle j'aimerais avoir vos avis sur le fond plus que la forme :

    La configuration QConfig :
    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
    typedef void(*Load)(); // Pointeur sur une méthode de chargement
     
    class QConfig
    {
      public :
        static void load(QString file); // Chargement du Dom depuis un fichier
        static void load(QString module, QMap<QString, QVariant>& params);
        static void attach(Load);
     
      private :
        static void notify();
     
      private :
        static QDomElement* M_pDom; // Stockage du dom
        static QList<Load> M_loads; // Liste des pointeurs sur les méthodes de chargement
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    bool QConfig::load(QString file)
    {
      /* bool ret = StockageDuDomEnVariableStaticPriv();
      if (success) */
        notify(); // Le dom étant chargé, on est prêt à récupérer les paramètres depuis les modules.
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void Config::notify()
    {
      for (int i=0; i<M_loads.size(); ++i)
        (*M_loads[i])();  // Appel aux méthodes statiques de chargement
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    bool QConfig::load(QString module, QMap<QString, QVariant>& params)
    {
      // Récupération des paramètres du module donné dans le dom
    }
    Un module QNetwork :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class QNetwork //: public QModule
    {
      public :
        static void loadParameters();
     
      private :
        static quint16 M_port;
    }
    Prise en compte du nouveau module pour le chargement des paramètres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QConfig::attach(QNetwork::loadParameters);
    La méthode de chargement des paramètres d'un module :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void QNetwork::loadParameters()
    {
      QMap<QString, QVariant> tabParams;
      tabParams.insert(CFG_PARAM_PORT, M_port);
      Config::load(CFG_MODULE_NETWORK, tabParams);
    }
    Qu'est ce que vous en pensez ?

    Merci

  8. #8
    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
    Si tu utilises Qt, utilises QSettings plutôt que de refaire quelque chose qui est similaire (sauf bien sûr à titre éducatif).

  9. #9
    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 skeud Voir le message
    Perso, je suis pas trop d'accord, dans tout mes projets (et projets professionnel) les classe de configuration sont des singleton renvoyant les différentes variables.
    Allez, un peu de lecture (ca faisait longtemps que je ne l'avais plus ressorti ce lien )
    Ce système permet de rajouté des variable dans le fichiers de configuration sans avoir à recodé une partie du programme.

    C'est beaucoup plus dynamique que d'avoir un membre d'une classe qui stock un paramètre. Imagine que tu doives rajouter x paramètre pour plusieurs classes, il faudra alors que tu re-développe les constructeurs de tes classes.

    Imagine une classe ayant besoin de 10 paramètre, tu vas pas appelé un constructeur avec 10 variable quand même?
    Imagine que ce constructeur soit appelé 50 fois dans ton code, tu vas aller modifié 50 fois ces lignes?
    Ah, ben, ca me fait penser à cette discussion sur laquelle j'ai été à peu pres le seul à répondre à impéro!

    Et je me suis même fendu d'un petit projet de "correction", qui utilise trois fichiers d'en-tête et que tu trouveras ==>ici<==

    Ne trouves tu pas cela plus propre
    C'est pourquoi je pense qu'il est nettement mieux de passer par un singleton pour la configuration, ce n'est pas une partie très sensible d'une application donc on peut se le permettre.
    C'est beaucoup plus sensible que tu ne pourrais le croire!

    Le problème du singleton, c'est que c'est forcément une variable globale, qui va donc maintenir globalement un ensemble d'informations dont certaines peuvent être sensibles (login et mot de passe, par exemple) et dont tu n'as globalement que faire dans la majorité des cas.

    Tu pourrais en arriver à créer un singleton par module, ce qui aurait au moins déjà l'avantage de faire en sorte que chaque module ne dispose que des informations dont il a réellement besoin.

    Mais c'est oublier un peu vite que chaque module est composé de plusieurs classes qui n'ont sans doute que faire de la plupart des informations auxquelles le singleton donne accès
    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

  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 sfarc Voir le message
    Bonjour et merci à tous les deux pour vos suggestions .
    C'est intéressant d'avoir ici deux points de vue!

    koala01 :

    Ok mais charge au(x) développeur(s) de faire attention à ne pas instancier un nouvel objet qui ferait doublon alors, c'est ça? Pourquoi rester trop permissif au niveau de la conception si au final on veut qu'une seule et unique instance ?
    Ca, ce n'est pas le plus compliqué...

    Tu peux, par exemple, envisager le recours au pimpl idiom:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class SoundConfig;
    class SoundModule{
        public:
           SoundModule(std::string const & configFilename);
           ~SoundModule();
            UnType const & getConfigValue( Identifiant id) const;
        private:
            SoundConfig * config_;
    };
    (UnType et Identifiant sont des types qui te seront utiles pour travailler qu'il s'agit de définir par toi même)
    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
    #include <SoundModule.h>
    class SoundConfig{
        public:
            SoundConfig(std::string const & configFilename){
                /* ... */
            }
            UnType getConfigValue(Identifiant id) const{
                /* ... */
            }
        private:
            std::map<Identifiant, UnType> infos_;
    }
    SoundModule::SoundModule(std::string const & configFilename):
        config_(new SoundConfig(configFilename){
     
    }
    SoundModule::~SoundModule(){
        delete config_;
    }
    UnType SoundModule::getConfigValue(Identifiant id) const{
        return config_->getConfigValue(id);
    }
    Comme tu n'auras, de toutes manières, qu'un seul module son dans ton application, tu auras la certitude qu'il n'y aura qu'une seule instance de SoundConfig et le développeur n'aura jamais la possibilité d'aller créer une nouvelle instance de SoundConfig
    En fait, j'avais envisagé de mettre mes paramètres de configuration par défaut en variable statique privée, ce qui réduit quand même la visibilité à la classe considérée, je trouve donc ça pas trop mal a priori.
    Comme je te l'ai dit, même si c'est une variable privée, cela en fait une variable globale (c'est le gros principe du mot clé static).

    Tu as beau la cacher, tu a beau en restreindre l'accès, ca reste une variable globale, et les variable globales, c'est mal
    Sinon, la Config serait aussi pour toi un objet instanciable classique ?
    A peu de chose près, oui.

    Mais elle serait beaucoup plus proche de la structure FILE que l'on a en C : Tout le monde sait qu'elle existe, mais personne ne sait ce qu'elle contient réellement et tout ce que l'on en sait, c'est la manière dont on peut l'utiliser.

    Dans l'exemple que je viens de donner, la seule chose que l'on en sait (et encore !!) c'est qu'on peut y accéder de manière indirecte au travers de SoundModule et de sa fonction membre getConfigValue
    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
    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
    Je me permet de revenir sur
    Citation Envoyé par skeud Voir le message
    Imagine une classe ayant besoin de 10 paramètre, tu vas pas appelé un constructeur avec 10 variable quand même?
    Je vais surtout voir à appeler le constructeur avec les paramètres dont il a réellement besoin pour fournir un objet cohérent, et veiller à ce que les autres paramètres soient transmis aux fonctions qui en ont besoin

    Parce que ce que j'ai dit au niveau de l'application et du module s'applique également au niveau de la classe : de nombreuses options utilisées au niveau de la classe ne sont utiles que pour certaines fonctions spécifiques (que ce soit le constructeur ou toute autre, fonction membre ou non, faisant partie de l'interface publique de l'objet en question).

    Si une classe n'a pas besoin d'une information dont une des fonctions spécifique a besoin, il faut juste veiller à transmettre cette information particulière à la fonction qui en a besoin
    Imagine que ce constructeur soit appelé 50 fois dans ton code, tu vas aller modifié 50 fois ces lignes?
    Je ferais surtout passer le développeur responsable de cet état de fait par la fenêtre avant, s'il a la chance d'en réchapper, de le faire écarteler tout en le faisant rotir à petit feu, histoire qu'il comprenne sa douleur

    La création d'objet doit être centralisée et la décision finale de créer ou non l'objet, en lui passant telle ou telle valeur issue de la configuration, doit dépendre d'un système qui permet justement de s'assurer -- de manière transparente pour celui qui demande la création de l'objet -- que l'objet sera créé "comme il se doit" pour respecter la configuration sans que l'utilisateur n'ai le moindre droit de regard sur cette configuration.

    Je m'explique :

    Mettons que l'utilisateur veuille créer un objet spécifique qui sera positionné à un endroit bien donné et que cet objet puisse être d'une couleur spécifiée par la configuration.

    Les seules informations que l'utilisateur doit transmettre au système qui se chargera de créer l'objet, c'est la position de celui-ci ainsi que les éventuelles informations qui permettront, d'une manière ou d'une autre, de déterminer si c'est un objet de type A ou un objet de type B qui sera réellement créé.

    Il n'a strictement que faire de savoir si l'objet en question sera, en fonction de la configuration, bleu ciel, rouge sang ou brun caca doigt

    Tout ce que l'utilisateur doit pouvoir faire, c'est demander au système concerné "crée moi tel objet à tel position" !

    Et c'est au système de déterminer si l’utilisateur a le droit ou non de créer l'objet demandé, quelle couleur lui donner et le meilleur moyen à utiliser pour parvenir au résultat escompté par l’utilisateur
    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

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    Allez, un peu de lecture (ca faisait longtemps que je ne l'avais plus ressorti ce lien )
    Sympa comme article . J'étais déjà tombé dessus mais ça fait pas de mal de le relire .

    Tu peux, par exemple, envisager le recours au pimpl idiom:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class SoundConfig;
    class SoundModule{
        public:
           SoundModule(std::string const & configFilename);
           ~SoundModule();
            UnType const & getConfigValue( Identifiant id) const;
        private:
            SoundConfig * config_;
    };
    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
    #include <SoundModule.h>
    class SoundConfig{
        public:
            SoundConfig(std::string const & configFilename){
                /* ... */
            }
            UnType getConfigValue(Identifiant id) const{
                /* ... */
            }
        private:
            std::map<Identifiant, UnType> infos_;
    }
    SoundModule::SoundModule(std::string const & configFilename):
        config_(new SoundConfig(configFilename){
     
    }
    SoundModule::~SoundModule(){
        delete config_;
    }
    UnType SoundModule::getConfigValue(Identifiant id) const{
        return config_->getConfigValue(id);
    }
    Comme tu n'auras, de toutes manières, qu'un seul module son dans ton application, tu auras la certitude qu'il n'y aura qu'une seule instance de SoundConfig et le développeur n'aura jamais la possibilité d'aller créer une nouvelle instance de SoundConfig
    Oui effectivement j'aurais qu'un seul module mais ce qui m'embête, c'est que rien ne l'impose. Rien n'empêche un développeur un jour d'instancier un nouveau module son par exemple même si c'est pas très fute fute.

    Aussi, autre point, l'idée de passer en paramètre du constructeur le chemin du fichier de configuration à chaque module me gène un peu. Cela voudrait dire, que chaque module, ou plutôt chaque objet conf associé a la possibilité de connaître l'ensemble du fichier. Je réfléchie à une alternative pour ce point là .

  13. #13
    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 sfarc Voir le message
    Aussi, autre point, l'idée de passer en paramètre du constructeur le chemin du fichier de configuration à chaque module me gène un peu. Cela voudrait dire, que chaque module, ou plutôt chaque objet conf associé a la possibilité de connaître l'ensemble du fichier. Je réfléchie à une alternative pour ce point là .
    De mon point de vue, un module doit se configurer… avec une structure qui lui est dédiée.

    Dans l’idéal, tu vas donc avoir :
    - un gestionnaire de settings, générique, qui s’occupe de la persistance (et donc, lecture / écriture du fichier de paramètres).
    - des classes / modules qui prennent quelque part, soit dans le constructeur, soit dans une méthode init, une structure/classe dédiée à leur configuration.
    - pour chaque module, un petit adaptateur qui va se charger de convertir les informations du fichier de configuration vers les classes de configuration, et vice-versa.

    Ainsi, tu as réellement un couplage faible entre la configuration de tes modules et la gestion de ton fichier de configuration. Après tout, le module n’a que faire que le paramètre vienne d’un fichier, de la ligne de commande, soit codé en dur ou encore calculé à partir de l’âge du capitaine : tout ce qu’il a besoin de savoir, c’est sa valeur.

  14. #14
    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 sfarc Voir le message
    Oui effectivement j'aurais qu'un seul module mais ce qui m'embête, c'est que rien ne l'impose. Rien n'empêche un développeur un jour d'instancier un nouveau module son par exemple même si c'est pas très fute fute.
    Ca, si le développeur fait une connerie, tu n'y peux rien

    Rend déjà ton module non copiable, non affectable.

    Place bien un cartouche sur ton module qui indique explicitement qu'il ne doit y avoir qu'un module de créé par l'application.

    Et si, malgré cela, le développeur ne sais pas lire, hé bien, tant pis pour lui
    Aussi, autre point, l'idée de passer en paramètre du constructeur le chemin du fichier de configuration à chaque module me gène un peu. Cela voudrait dire, que chaque module, ou plutôt chaque objet conf associé a la possibilité de connaître l'ensemble du fichier. Je réfléchie à une alternative pour ce point là .
    Ne te bloque pas vraiment sur les paramètres que j'ai passé au constructeur de SoundModule.

    L'exemple portait surtout sur le pimple idiome, car, rien n'empêche que le nom du fichier de configuration soit inscrit en dur dans le constructeur de SoundModule (ou meme de SoundConfig)

    Citation Envoyé par white_tentacle Voir le message
    De mon point de vue, un module doit se configurer… avec une structure qui lui est dédiée.

    Dans l’idéal, tu vas donc avoir :
    - un gestionnaire de settings, générique, qui s’occupe de la persistance (et donc, lecture / écriture du fichier de paramètres).
    - des classes / modules qui prennent quelque part, soit dans le constructeur, soit dans une méthode init, une structure/classe dédiée à leur configuration.
    - pour chaque module, un petit adaptateur qui va se charger de convertir les informations du fichier de configuration vers les classes de configuration, et vice-versa.

    Ainsi, tu as réellement un couplage faible entre la configuration de tes modules et la gestion de ton fichier de configuration. Après tout, le module n’a que faire que le paramètre vienne d’un fichier, de la ligne de commande, soit codé en dur ou encore calculé à partir de l’âge du capitaine : tout ce qu’il a besoin de savoir, c’est sa valeur.
    Exactement
    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

  15. #15
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2008
    Messages : 308
    Points : 622
    Points
    622
    Par défaut
    L'article met l'accent sur le fait que le singleton permet de faire deux choses
    -Garantir l'unicité
    -Permettre l’accès à l'instance de n'importe où
    Mais on pourrais créer un speudo-singleton qui se contente de garantir l'unicité, en implémentant un singleton à la différence prêt que le "getInstance" renverrait NULL ou une exception si l'instance existe déjà. Après il reste toujours la variable globale déguisée, doit on réellement bannir l'utilisation des variables static ?

  16. #16
    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 bebaijhi Voir le message
    Après il reste toujours la variable globale déguisée, doit on réellement bannir l'utilisation des variables static ?
    Je n'irai pas jusqu'à dire qu'il faut les bannir, mais il faut réellement se poser la question de savoir si l'on en a réellement besoin (AKA s'il n'y a vraiment pas d'alternative), surtout si c'est une variable non constante.

    Que tu définisses une variable static const int xxMax pour indiquer une limite qui ne sera jamais atteinte est une chose qui peut sembler cohérente (toutes les instances de ta classe partagent la même valeur, et c'est une bonne chose).

    Mais que tu crées une variable statique non constante qui peut, par définition, être modifiée depuis "n'importe où" dans le code n'ira jamais sans poser de problème. Ne serait-ce que parce que, justement, tu laisses la possibilité de la modifier depuis "n'importe où".

    Or, à moins de définir une amitié pour permette à une seule classe de modifier l'état de ta variable statique, tu vas exposer les accesseurs sur le contenu de l'ensemble de ta configuration (il faut bien, si tu veux pouvoir en récupérer les valeurs ), quitte à ce qu'il n'y ait qu'une seule fonction qui remplisse office.

    Mais tu exposeras également les mutateurs (ou la fonction unique qui en fait office), et donc, tu donneras de facto la possibilité de changer ces valeurs.

    Et c'est à ce moment là que les problèmes apparaîtront, parce que tu en arriveras fatalement tôt ou tard à modifier l'une des valeurs à un endroit où tu n'aurais pas du le faire .

    C'est pour cela que je n'ai rien contre le fait de regrouper, d'une manière ou d'une autre, toutes les informations de configuration d'un module en un point précis, mais que je dis qu'il faut veiller à ce que ces informations ne soient transmises qu'aux classes et fonction qui en ont 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

  17. #17
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    Rend déjà ton module non copiable, non affectable.
    Oui je vais déjà faire ça
    Mais le fait de faire confiance aux développeurs ne témoigne pas d'une faille dans la conception ?
    C'est vraiment ce qui me gène. Pour moi, défini de la sorte, on peut avoir dans l'absolu plusieurs instances de la classe.

    Voici l'implémentation que je propose suite à vos suggestions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class QNetwork : public QModule
    {
      public :
        QNetwork() : QModule(), m_config(new QNetworkConfig())
     {}
        ~QNetwork(); // se charge de détruire m_config
     
      private :
        QNetworkConfig* m_config;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class QNetworkConfig
    {
      public :
        QNetworkConfig();
     
      private :
        quint16 m_port;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    QNetworkConfig::QNetworkConfig()
    , m_port(CFG_PARAM_PORT_DEFAULT_VALUE)
    {
      if (QConfig::load(CFG_FILE_NETWORK)) // Finalement, chaque module aura son propre fichier de config
      {
        QConfig::getParam<int>(CFG_PARAM_PORT, m_port); // Se serait mieux de spécialiser getParam en quint16 non ?
      }
    }
    Et pour le chargement d'un fichier de configuration et la lecture de paramètres, j'ai tout de même conserver des méthodes statiques avec une variable statique privée pour le dom :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class QConfig
    {
      public :
        static bool load(const QString&);
     
        template <typename T>
        static bool getParam(const QString&, T&);
     
      private :
        static QDomDocument M_dom;
    }
    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
    bool getParam(const QString& key, T& value)
    {
      QDomElement root = M_dom.documentElement();
      QDomNode node = root.firstChild();
      QDomElement element;
      while (!node.isNull())
      {
        element = node.toElement();
        if (element.tagName() == key)
        {
          value = element.text();
          return true;
        }
      }
     
      return false;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Spécialisation pour les int
    template<>
    bool QConfig::getParam<int>(const QString& key, int& value)
    {
      bool ret;
      QString text;
      if (ret = getParam<QString>(key, text))
        value = text.toInt(&ret);
     
      return ret;
    }
    Qu'en pensez-vous ?

  18. #18
    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 sfarc Voir le message
    Oui je vais déjà faire ça
    Mais le fait de faire confiance aux développeurs ne témoigne pas d'une faille dans la conception ?
    A vrai dire, je ne vois pas pourquoi...

    Il y a "toutes les chances" pour qu'il ne doive exister qu'une instance de tes différents modules, mais qu'est ce qui justifierait que ce ne soit pas le cas

    Qu'est ce qui pourrait empêcher le développeur de vouloir explicitement lancer deux instances particulière du même module

    En obligeant le développeur à n'en créer qu'une instance, tu prends une décision arbitraire qui, bien que cohérente de ton point de vue n'est peut être pas forcément en accord avec les besoins du développeur

    Signale lui bien que, normalement, une seule instance devrait suffire, mais, s'il a besoin d'en avoir plusieurs (pour quelque raison que ce soit ), pourquoi le lui refuser
    C'est vraiment ce qui me gène. Pour moi, défini de la sorte, on peut avoir dans l'absolu plusieurs instances de la classe.
    Effectivement, dans l'absolu, on peut envisager d'avoir plusieurs instances... Et pourquoi ne devrait-ce pas être le cas dans certaines situations bien particulières
    Voici l'implémentation que je propose suite à vos suggestions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class QNetwork : public QModule
    {
      public :
        QNetwork() : QModule(), m_config(new QNetworkConfig())
     {}
        ~QNetwork(); // se charge de détruire m_config
     
      private :
        QNetworkConfig* m_config;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class QNetworkConfig
    {
      public :
        QNetworkConfig();
     
      private :
        quint16 m_port;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    QNetworkConfig::QNetworkConfig()
    , m_port(CFG_PARAM_PORT_DEFAULT_VALUE)
    {
      if (QConfig::load(CFG_FILE_NETWORK)) // Finalement, chaque module aura son propre fichier de config
      {
        QConfig::getParam<int>(CFG_PARAM_PORT, m_port); // Se serait mieux de spécialiser getParam en quint16 non ?
      }
    }
    je ne suis pas fan de l'utilisation des directive #define du préprocesseur

    Tu as raison d'éviter les nombres magiques, mais tu devrais plutôt soit utiliser une valeur numérique réelle (un int, par exemple) constant, soit une valeur énumérée.

    Cela t'évitera sans doute bien des problèmes si tu utilise cette valeur à mauvais escient
    Et pour le chargement d'un fichier de configuration et la lecture de paramètres, j'ai tout de même conserver des méthodes statiques avec une variable statique privée pour le dom :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class QConfig
    {
      public :
        static bool load(const QString&);
     
        template <typename T>
        static bool getParam(const QString&, T&);
     
      private :
        static QDomDocument M_dom;
    }
    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
    bool getParam(const QString& key, T& value)
    {
      QDomElement root = M_dom.documentElement();
      QDomNode node = root.firstChild();
      QDomElement element;
      while (!node.isNull())
      {
        element = node.toElement();
        if (element.tagName() == key)
        {
          value = element.text();
          return true;
        }
      }
     
      return false;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Spécialisation pour les int
    template<>
    bool QConfig::getParam<int>(const QString& key, int& value)
    {
      bool ret;
      QString text;
      if (ret = getParam<QString>(key, text))
        value = text.toInt(&ret);
     
      return ret;
    }
    Qu'en pensez-vous ?
    Pourquoi rendre la fonction load et le document statiques

    A prior, tu as de toutes façons une configuration qui est créée. Autant appeler la fonction load depuis l'instance qui est créée, autrement, tu devras de toutes manières transmettre cette configuration en paramètre pour pouvoir la mettre à jour
    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

  19. #19
    Membre du Club
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 99
    Points : 58
    Points
    58
    Par défaut
    En obligeant le développeur à n'en créer qu'une instance, tu prends une décision arbitraire qui, bien que cohérente de ton point de vue n'est peut être pas forcément en accord avec les besoins du développeur
    dans l'absolu, on peut envisager d'avoir plusieurs instances... Et pourquoi ne devrait-ce pas être le cas dans certaines situations bien particulières
    Je comprends ce que tu veux dire. En fait, l'idée n'est pas de fournir une API à des développeurs mais plutôt de concevoir ma propre application, d'où ma gêne à laisser autant de liberté à d'éventuels développeurs de la revoir, quitte à ce que l'application perde de son sens.

    je ne suis pas fan de l'utilisation des directive #define du préprocesseur
    tu devrais plutôt soit utiliser une valeur numérique réelle (un int, par exemple) constant, soit une valeur énumérée.
    Cela t'évitera sans doute bien des problèmes si tu utilise cette valeur à mauvais escient
    Qu'est ce que les valeurs numériques réelles apportent en plus ici ? un type précis pour le compilateur par exemple ?

    Pourquoi rendre la fonction load et le document statiques
    Ici, pour chaque configuration de module, j'avais besoin d'une factorisation de code pour charger un fichier et récupérer les paramètres. Je ne me voyais pas définir un même objet config à instancier dans chaque configuration de module car je trouve ça redondant et je ne me voyais pas passer en paramètre une référence sur la config à chaque module. Tu avais envisagé l'une de ces solutions ?

    A prior, tu as de toutes façons une configuration qui est créée. Autant appeler la fonction load depuis l'instance qui est créée, autrement, tu devras de toutes manières transmettre cette configuration en paramètre pour pouvoir la mettre à jour
    Tu veux dire appeler load depuis chaque configuration de module ?
    Je ne vois pas bien ce que tu suggères ici .

    Aussi, un point qui m'embête assez souvent dans ma conception, c'est le fait de ne pas pouvoir appeler depuis le constructeur des méthode virtuelles à cause de la vtable qui n'est pas encore créée. Je sais qu'il suffit de définir une méthode a appeler après le constructeur comme Init() mais ça m'embête de ne pas avoir, dés la construction de l'objet (seul appel du constructeur), l'objet entièrement initialisé et prêt. Comment vous faites pour contourner ce problème classique ?

  20. #20
    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 sfarc Voir le message
    Je comprends ce que tu veux dire. En fait, l'idée n'est pas de fournir une API à des développeurs mais plutôt de concevoir ma propre application, d'où ma gêne à laisser autant de liberté à d'éventuels développeurs de la revoir, quitte à ce que l'application perde de son sens.
    Tu n'as pas vraiment à t'inquiéter de cela...

    pour chaque module, tu auras une sorte de "façade" qui permettra à ce module d'interagir avec les autres.

    Tu charges ta configuration au niveau de cette façade et tu veilles à ce que chaque fonctionnalité accessible depuis la façade fournisse aux différents éléments du module les données de configuration dont ils ont besoin pour fonctionner.

    Ton module devient une sorte de "boite noire" au départ de laquelle seules les fonctionnalités exposées par la façade sont accessibles pour "le monde extérieur", et, si tu as besoin, à l'intérieur du module concerné, des fonctionnalités offertes par la façade, tu travailles avec des références et/ou des pointeurs.

    Le seul endroit où le module est instancié, c'est d'office l'application (qui va utiliser différents modules). Tu n'as donc pas à t'inquiéter de rendre ton module unique, vu qu'il l'est déjà de facto

    Et si un développeur décide de créer une deuxième instance de ton module, a priori, soit il fait une erreur dont il se rendra rapidement compte, soit il sait pertinemment ce qu'il fait. Quoi qu'il en soit, cela ne te concerne pas
    Qu'est ce que les valeurs numériques réelles apportent en plus ici ? un type précis pour le compilateur par exemple ?
    Essentiellement, oui.
    Ici, pour chaque configuration de module, j'avais besoin d'une factorisation de code pour charger un fichier et récupérer les paramètres. Je ne me voyais pas définir un même objet config à instancier dans chaque configuration de module car je trouve ça redondant et je ne me voyais pas passer en paramètre une référence sur la config à chaque module. Tu avais envisagé l'une de ces solutions ?
    Bien sur que tu ne vas pas instancier une configuration par information que contient ton fichier de config (enfin, tu vas instancier une ConfigurationInfo quand même, quelle qu'en soit la forme).

    Mais, comme je te l'ai dit plus haut, le module son n'a absolument que faire des informations de configuration du module réseau qui n'a absolument que faire des informations de configuration du module graphique qui n'a absolument que faire des informations de configuration du module métier.

    Que les informations de configuration soient représentée sous une forme relativement commune (comprends : qu'une information de couleur par exemple soit représentée sous la même forme quel que soit le module qui l'utilise) est normal et tout à fait cohérent.

    Que les informations de configuration soient centralisées dans un fichier unique est envisageable, mais tu dois veiller à ce que chaque module ne dispose que des informations qui le concernent directement
    Tu veux dire appeler load depuis chaque configuration de module ?
    Je ne vois pas bien ce que tu suggères ici .
    Effectivement, c'est ce que je suggère.

    Si tu décides de travailler avec un fichier xml, grand bien te fasse. Tu peux tout à fait factoriser le code de récupération / création des différentes informations de configuration. Mais pas au niveau de la configuration elle-même : au niveau "du système responsable de la subsistance / sérialisation / désérialisation" de tes informations de connexions.

    Et cela peut, parfaitement, aussi prendre la forme d'une fonction libre. Il n'est pas indispensable de vouloir respecter à tout prix le paradigme OO plus que de raison

    D'une certaine manière, c'est ce que Stroutroup reproche au terme paradigme : si on en croit wikipedia, ce sont des rails dont il ne faut pas s'écarter. Or, C++ est multi - paradigme. Ce qui fait que tu peux choisir le meilleur de tous les paradigmes possibles pour résoudre un problème particulier
    Aussi, un point qui m'embête assez souvent dans ma conception, c'est le fait de ne pas pouvoir appeler depuis le constructeur des méthode virtuelles à cause de la vtable qui n'est pas encore créée. Je sais qu'il suffit de définir une méthode a appeler après le constructeur comme Init() mais ça m'embête de ne pas avoir, dés la construction de l'objet (seul appel du constructeur), l'objet entièrement initialisé et prêt. Comment vous faites pour contourner ce problème classique ?
    1- Je respecte scrupuleusement le SRP (Single Responsability Principle ou, si tu préfères, le principe de la responsabilité unique) : je définis clairement la responsabilité de chaque classe afin de savoir quel(s) service(s) je suis en droit d'attendre

    2- Je me méfie comme de la peste des termes "gérer", "manager", "système" et autres : Bien souvent, ce sont des termes qui méritent des précisions et qui englobent plusieurs responsabilités qui peuvent être déléguées à plusieurs classes distinctes.

    3- je ne fais jamais dépendre une classe de base d'une donnée d'une classe dérivée. Au pire, je fais l'inverse.

    4 - j'utilise tous les outils à ma disposition : le paradigme impératif, le paradigme OO, le paradigme générique en fonction des circonstances afin d'en tirer le meilleur parti et les différents patrons de conception mis à ma disposition (à l'exception notable du singleton )

    5- je respecte l'OCP (Open/Close Principle)

    6- De manière générale, j'ai six dieux et une profession de foi : la loi de Déméter, les principe SOLID et la citation de David Wheeler : Tout problème en informatique peut être résolu par une indirection supplémentaire (mais en occasionne souvent un autre)

    Y en a sans doute d'autres, mais si tu suis déjà ces six points, tu auras fait un très grand pas dans la bonne direction
    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

Discussions similaires

  1. [Conception] - Chargement
    Par defkid dans le forum Général Java
    Réponses: 5
    Dernier message: 24/10/2005, 17h20
  2. Gestion des départements problème de conception
    Par snoopy69 dans le forum Modélisation
    Réponses: 7
    Dernier message: 11/10/2005, 13h08
  3. Réponses: 3
    Dernier message: 08/12/2004, 21h11
  4. Problème de conceptions de tables
    Par dtavan dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 23/05/2004, 23h13
  5. Problème lors du chargement
    Par carlito dans le forum Flash
    Réponses: 26
    Dernier message: 06/01/2004, 15h21

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