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 :

Recherche du bon design pattern (ou pas)


Sujet :

C++

  1. #1
    Futur Membre du Club
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Juillet 2016
    Messages
    5
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 45
    Localisation : France, Ain (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : D�veloppeur informatique

    Informations forums :
    Inscription : Juillet 2016
    Messages : 5
    Par d�faut Recherche du bon design pattern (ou pas)
    Bonsoir � tous,

    voil� ma probl�matique :
    J'ai une classe m�re M et plusieurs classes filles F1, F2, etc... Ces classes repr�sentent les colonnes d'un tableau qui contient des types de donn�es diff�rents (double, string, etc..)

    Je r�cup�re les donn�es au fur et � mesure et je souhaite pouvoir modifier le type d'une colonne d'un type fille vers un autre type fille au fur et � mesure que j'analyse les donn�es que je re�ois. Si vous vous demandez "pourquoi ne pas le faire � la fin ?", la r�ponse est "pour gagner de l'espace m�moire", si je d�tecte qu'il s'agit d'entiers par exemple, je m'�vite de les stocker sous forme de string.

    Bien s�r, la solution de base serait de cr�er � chaque fois une nouvelle instance fille du bon type, faire la copie puis supprimer l'ancienne... N�anmoins, c'est lourdingue et qui plus est, ce type de traitement doit �tre assez commun et j'ai l'impression qu'il doit surement y avoir un design pattern de derri�re les fagots qui s'applique parfaitement � ce genre de probl�matique.

    Est-ce que quelqu'un a d�j� �t� confront� � ce genre de probl�me ? Avez-vous des solutions ou des pistes � proposer ?

    Merci d'avance,

    d!

  2. #2
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    �tudiant
    Inscrit en
    F�vrier 2012
    Messages
    788
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 35
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : F�vrier 2012
    Messages : 788
    Par d�faut
    Bonjour

    Un boost::variant (accept� pour C++17), associ� au bon visteur, ne r�glerait pas le souci ?

  3. #3
    Futur Membre du Club
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Juillet 2016
    Messages
    5
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 45
    Localisation : France, Ain (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : D�veloppeur informatique

    Informations forums :
    Inscription : Juillet 2016
    Messages : 5
    Par d�faut
    Merci pour cette r�ponse. Elle ne r�sout pas mon probl�me, mais elle pourrait m'aider pour la suite.

    En fait, je ne veux pas seulement traiter la donn�e que je re�ois � la vol�e mais aussi la stocker (et donc potentiellement la reconvertir � la vol�e par la suite).

    Un exemple :
    Pour ma premi�re colonne je lis une chaine de caract�res correspondant � un entier comme premi�re valeur => Je cr�e un objet ColonneDEntier qui contient un vector<int> et qui a certaines propri�t�s
    Pareil pour les dix valeurs suivantes => je continue de stocker dans mon vecteur d'entiers
    A la 12eme valeur, j'ai un nombre flottant => je veux convertir mon objet ColonneDEntier en ColonneDeFlottant qui contient un vector<float> et des propri�t�s diff�rentes.

    Je sais que je n'�chapperai pas � la copie (avec conversion) du contenu de vector<int> dans vector<float>, mais j'aimerai m'�viter la construction/destruction d'objets ColonneDeXxxx. Etant donn� que ma classe qui stocke l'ensemble contient un vector<Colonne> (classe m�re), je voudrais �viter d'avoir � lui faire g�rer plein de v�rifications de types pour savoir quels sont les new sp�cifiques qu'il doit faire.

    Si je sch�matise l'algo, j'ai quelque chose dans ce go�t la :

    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
     
    vector<Colonne *> monTableau;
     
    nbColonnes = lirePremierligne(); //La premiere ligne me permet juste de définir le nombre de colonnes, je ne traite pas son contenu
    monTableau.resize(nbColonnes);
    for (int i = 0; i < nbColonnes; ++i)
         monTableau[i] = new ColonneDeBooleens();   //J'initialise avec Booleen car c'est le type le plus restrictif dans mon cas
     
    lireChaqueLigne()
         pourChaqueValeurDeLaLigne()
              monTableau[i]->ajouteElement(valeur);  //La méthode ajoute élément vérifie si 'valeur' correspond bien au type courant de la colonne
     
              // Le cas échéant, je pourrais imaginer avoir ici quelque chose qui récupère le nouveau type et qui fait un truc du genre....
              switch (nouveauTypeColonne)
              {
                   case TypeTruc : ColonneDeTruc *nouvelleCol = new ColonneDeTruc(monTableau[i]); // Avec du coup, un constructeur par recopie de chaque type vers chaque type...
                        monTableau.remove(i);
                        monTableau.insert(i, nouvelleCol);
                        break;
                   case ... // Pareil pour chaque type
              }
              // ... Mais je voudrais éviter parce que je trouve ça crado... ^^
     
    Voilà, j'espère que c'est un peu plus clair.
     
    Merci pour vos réponses et suggestions. :)
     
    d!

  4. #4
    Expert confirm�

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

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par d�faut
    Tu lis une premi�re ligne, qui te permet de d�terminer le type de chaque colonne?
    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).

  5. #5
    Futur Membre du Club
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Juillet 2016
    Messages
    5
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 45
    Localisation : France, Ain (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : D�veloppeur informatique

    Informations forums :
    Inscription : Juillet 2016
    Messages : 5
    Par d�faut
    Citation Envoy� par dragonjoker59 Voir le message
    Tu lis une premi�re ligne, qui te permet de d�terminer le type de chaque colonne?
    Non, je choisi le type de fa�on arbitraire au d�part.

  6. #6
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyr�n�es)

    Informations professionnelles :
    Activit� : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par d�faut
    C'est un exercice int�ressant.

    Proposition :
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    class ColonneAbstraite
    {
    public:
        virtual ~ColonneAbstraite() {}
        virtual void ajouteElement(Tableau& parent, size_t indiceDeMoiMemeDansParent, const std::string& valeur) = 0;
            // Si la valeur n'a pas le bon type, créer une nouvelle colonne,
            // l'insérer dans le tableau à notre place et se suicider.
        // ...
    };
     
    class Tableau
    {
    private:
        std::vector<std::unique_ptr<ColonneAbstraite>> m_colonnes;
    public:
        std::unique_ptr<ColonneAbstraite> libererColonne(size_t indice) {
            assert(indice < m_colonnes.size());
            return std::move(m_colonnes[indice]);
        }
        void setColonne(size_t indiceColonne, std::unique_ptr<ColonneAbstraite> nouvelleColonne) {
            assert(indiceColonne < m_colonnes.size());
            m_colonnes[indiceColonne] = std::move(nouvelleColonne);
        }
        void ajouteElement(size_t indiceColonne, const std::string& valeur) {
            assert(indiceColonne < m_colonnes.size());
            m_colonnes[indiceColonne]->ajouteElement(*this, indiceColonne, valeur);
        }
        // ...
    };
     
    class ColonneChaines : public ColonneAbstraite { /* ... */ };
     
    class ColonneEntiers : public ColonneAbstraite { /* ... */ };
     
    class ColonneBooleens : public ColonneAbstraite
    {
    private:
        std::vector<bool> m_cellules;
    public:
        virtual ~ColonneBooleens() {}
        void ajouteElement(Tableau& parent, size_t indiceDeMoiMemeDansParent, const std::string& valeur) override
        {
            boost::optional<bool> valeurBooleenne = convertirEnBooleen(valeur);
            if(valeurBooleenne) {
                m_cellules.push_back(*valeurBooleenne);
            } else {
                std::unique_ptr<ColonneAbstraite> nouvelleColonne;
                boost::optional<int> valeurEntiere = convertirEnEntier(valeur);
                if(valeurEntiere) {
                    std::unique_ptr<ColonneEntiers> nouvelleColonneEntiers(new ColonneEntiers(*this));
                    nouvelleColonneEntiers->ajouterEntier(*valeurEntiere);
                    nouvelleColonne = std::move(nouvelleColonneEntiers);
                } else {
                    std::unique_ptr<ColonneChaines> nouvelleColonneChaines(new ColonneChaines(*this));
                    nouvelleColonneChaines->ajouterChaine(valeur);
                    nouvelleColonne = std::move(nouvelleColonneChaines);
                }
                std::unique_ptr<ColonneAbstraite> moi = parent.libererColonne(indiceDeMoiMemeDansParent);
                assert(moi.get() == this);
                parent.setColonne(indiceDeMoiMemeDansParent, std::move(nouvelleColonne));
            }
        }
        // ...
    };

  7. #7
    Membre Expert
    Homme Profil pro
    Ing�nieur d�veloppement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, H�rault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par d�faut
    J'ai essay� avec un variant et semble me semble plus simple avec moins de risque d'oublier une conversion: cela ne compilerait pas (ex std::vector<int> -> std::vector<std::string>).

    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <boost/variant.hpp>
    #include <type_traits>
    #include <vector>
     
    struct Colonne
    {
      template<class T>
      void ajouteElement(T x) {
        boost::apply_visitor([&x, this](auto & vec) {
          this->ajouteElement_impl(vec, x);
        }, variant);
      }
     
      template<class Visitor>
      void apply(Visitor v) const {
        boost::apply_visitor(v, variant);
      }
     
    private:
      template<class T>
      void ajouteElement_impl(std::vector<T> & vec, T x) {
        vec.push_back(x);
      }
     
      template<class T, class U>
      std::enable_if_t<std::is_arithmetic<T>{} && std::is_arithmetic<U>{}>
      ajouteElement_impl(std::vector<T> & vec, U x) {
        std::vector<U> new_vec(begin(vec), end(vec));
        new_vec.push_back(x);
        variant = std::move(new_vec);
      }
     
      boost::variant<std::vector<bool>, std::vector<float>, std::vector<int>> variant;
    };
     
     
    #include <iostream>
     
    char const * get_type(std::vector<float> const &) { return "vector<float>"; }
    char const * get_type(std::vector<bool> const &) { return "vector<bool>"; }
    char const * get_type(std::vector<int> const &) { return "vector<int>"; }
     
    std::ostream & operator << (std::ostream & out, Colonne const & colonne) {
      colonne.apply([&out](auto & vec) {
        out << get_type(vec) << ": ";
        for (auto && x : vec) {
          out << x << ", ";
        }
      });
      return out;
    }
     
    int main() {
     
    Colonne colonne;
    colonne.ajouteElement(1); // int
    std::cout << colonne << "\n";
    colonne.ajouteElement(1.4f); // float
    std::cout << colonne << "\n";
    colonne.ajouteElement(0); // int
    std::cout << colonne << "\n";
    colonne.ajouteElement(true); // bool
    std::cout << colonne << "\n";
    colonne.ajouteElement(false); // bool
    std::cout << colonne << "\n";
     
    }
    R�sultat:
    vector<int>: 1,
    vector<float>: 1, 1.4,
    vector<int>: 1, 1, 0,
    vector<bool>: 1, 1, 0, 1,
    vector<bool>: 1, 1, 0, 1, 0,

  8. #8
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyr�n�es)

    Informations professionnelles :
    Activit� : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par d�faut
    Citation Envoy� par jo_link_noir Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
      template<class T, class U>
      std::enable_if_t<std::is_arithmetic<T>{} && std::is_arithmetic<U>{}>
      ajouteElement_impl(std::vector<T> & vec, U x) {
        std::vector<U> new_vec(begin(vec), end(vec));
        new_vec.push_back(x);
        variant = std::move(new_vec);
      }
    Citation Envoy� par jo_link_noir Voir le message
    R�sultat:
    vector<int>: 1,
    vector<float>: 1, 1.4,
    vector<int>: 1, 1, 0,
    vector<bool>: 1, 1, 0, 1,
    vector<bool>: 1, 1, 0, 1, 0,
    Je crois que �a ne correspond pas au besoin de d000x.
    De ce que j'ai compris, quand il a une colonne avec des �l�ments de type T et qu'on ajoute un �l�ment de type U, la colonne doit avoir des �l�ments de type max(T,U) selon la relation d'ordre :
    bool < int < double < std::string.
    Par contre, dans ce que tu as cod�, la colonne se retrouve toujours avec des �l�ments de type U.

    Il faudrait complexifier le code en utilisant quelque chose dans ce genre-l� :
    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
    template<class T, class U>
    struct pairTypes
    {
    };
     
    template<> struct pairTypes<std::string, int> { typedef std::string typeEnglobant; };
    template<> struct pairTypes<bool, int>        { typedef int         typeEnglobant; };
    // autres spécialisations...
     
    template<class T, class U>
    T convertirVers(const U& x) {
        return x;
    }
     
    template<> std::string convertirVers<std::string>(const int& x) { return std::to_string(x); }
    // autres spécialisations...
     
    template<class T, class U>
    typename pairTypes<T, U>::typeEnglobant
    convertirVersTypeEnglobant(U x) {
        return convertirVers<typename pairTypes<T, U>::typeEnglobant>(x);
    }

  9. #9
    Futur Membre du Club
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Juillet 2016
    Messages
    5
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 45
    Localisation : France, Ain (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : D�veloppeur informatique

    Informations forums :
    Inscription : Juillet 2016
    Messages : 5
    Par d�faut
    Bonjour,

    tout d'abord, merci � vous deux pour vos r�ponses.

    Citation Envoy� par Pyramidev Voir le message
    Je crois que �a ne correspond pas au besoin de d000x.
    De ce que j'ai compris, quand il a une colonne avec des �l�ments de type T et qu'on ajoute un �l�ment de type U, la colonne doit avoir des �l�ments de type max(T,U) selon la relation d'ordre :
    bool < int < double < std::string.
    Par contre, dans ce que tu as cod�, la colonne se retrouve toujours avec des �l�ments de type U.
    en effet! Qui plus est pour des raisons techniques, je ne peux pas utiliser de templates ici.

    La solution de Pyramidev correspond plus � mon besoin. Je n'avais pas vu la r�ponse plus t�t, du coup en attendant j'ai opt� pour une solution moins "propre", je vous la livre ici purement � titre d'info :

    Je n'ai plus qu'une seule classe de Colonne ind�finie. Cette colonne contient tous les types (je pars du principe qu'un vector<> vide ne coute pas beaucoup de place de stockage...). Du coup, lors d'un changement de type, j'ai juste � transf�rer les donn�es d'un vector � un autre sans avoir � me soucier de l'objet Colonne en lui m�me qui ne bouge pas.

    Ci-dessous une version "sale et simplifi�e" de ce que �a peut donner...

    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
     
     
    	void Colonne::addElement(const std::string &element)
    	{
                    checkType(element);
    		switch (_type)
    		{
    		case booleen:
    			_boolValues[_curElem++] = element;
    			break;
    		case float:
    			_floatValues[_curElem++] = atof(element.c_str());
    			break;
    		case int:
    			_intValues[_curElem++] = atoi(element.c_str());
    			break;
    		}
    	}
     
     
            void Colonne::checkType(const string &element) {
    		if (_type == bool && !isBoolean(element))
    		{
    			if (!isInteger(element))
                            {
                                    _type = float;
    			        convertFromBoolToFloat();
                            }
    			else
                            {
                                    _type = int;
    				convertFromBoolToInt();
    			}
    		}
    		if (_type == int && !isInteger(element))
                    {
                            _type = float;
    		        convertFromIntToFloat();
    		}
    	}
     
     
            void Colonne::convertFromIntToFloat()
    	{
    		_floatValues.resize(_nbElem);
     
    		for (size_t count = 0; count < _curElem; ++count)
    			_floatValues[count] = _intValues[count];
     
    		_intValues.clear();
    	}
     
            void Colonne::convertFromBoolToFloat()
            { }
            void Colonne::convertFromBoolToInt()
            { }
     
             /* .... */
    La solution de Pyramidev me para�t tr�s bien, je vais gratter dans ce filon.

    Merci encore !

    d!

  10. #10
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    �tudiant
    Inscrit en
    F�vrier 2012
    Messages
    788
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 35
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant
    Secteur : High Tech - �diteur de logiciels

    Informations forums :
    Inscription : F�vrier 2012
    Messages : 788
    Par d�faut
    Citation Envoy� par d000x Voir le message
    Qui plus est pour des raisons techniques, je ne peux pas utiliser de templates ici.
    �a ne doit pas �tre tout � fait les vraies contraintes car std::vector et std::string sont templates

  11. #11
    Futur Membre du Club
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Juillet 2016
    Messages
    5
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 45
    Localisation : France, Ain (Rh�ne Alpes)

    Informations professionnelles :
    Activit� : D�veloppeur informatique

    Informations forums :
    Inscription : Juillet 2016
    Messages : 5
    Par d�faut
    Citation Envoy� par Ehonn Voir le message
    �a ne doit pas �tre tout � fait les vraies contraintes car std::vector et std::string sont templates
    Je ne voulais pas dire que je ne pouvais pas utiliser de classe template, juste que je ne pouvais pas "templater" mes propres classes

Discussions similaires

  1. Le bon design pattern.
    Par Ali Kent dans le forum UML
    R�ponses: 2
    Dernier message: 10/01/2015, 15h49
  2. [Couplage] Bon design pattern pour synchroniser deux modules (Adapter, Observer ?)
    Par Steph0 dans le forum Design Patterns
    R�ponses: 2
    Dernier message: 21/06/2013, 14h16
  3. [PHP 5.1] A la recherche d'un design pattern
    Par Invit� dans le forum Langage
    R�ponses: 1
    Dernier message: 27/08/2010, 13h35
  4. [Composite] Recherche d'un design pattern proche
    Par telluri dans le forum Design Patterns
    R�ponses: 7
    Dernier message: 03/04/2010, 17h21
  5. Design Pattern ou pas ?
    Par jc63 dans le forum Design Patterns
    R�ponses: 3
    Dernier message: 13/08/2009, 23h22

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