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++/CLI Discussion :

Design de polymorphisme li� � des if / else


Sujet :

C++/CLI

Vue hybride

Message pr�c�dent Message pr�c�dent   Message suivant Message suivant
  1. #1
    Membre confirm�
    Inscrit en
    F�vrier 2013
    Messages
    94
    D�tails du profil
    Informations forums :
    Inscription : F�vrier 2013
    Messages : 94
    Par d�faut Design de polymorphisme li� � des if / else
    Bonjour � toutes et � tous,
    Je parcourais Stack ce matin, et je suis tomb� sur ce sujet de polymorphisme:
    https://stackoverflow.com/questions/...use-it-outside
    En particulier sur ce bout de code:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Alma* Andor;
     
     if(b00lvar){
        Andor = new Birs();
        std::cout<<Andor->Getwidth()<<" "<<Andor->Getheight()<<std::endl;
      }else{
        Andor = new Citrom();  
        std::cout<<Andor->Getwidth()<<" "<<Andor->Getdepth()<<std::endl;
      }
    post� en r�ponse. On voit ici que l'initialisation de la classe d�pend d'une variable 'b00lvar'. Je me posais la question d'un cas plus large, ou nous aurions une classe de base et beaucoup de classes filles, suivant le m�me sch�ma, par exemple:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Alma* Andor;
     
    switch( une_variable ) {
      case 0 : { Andor = new Birs(param1, param2); }
      case 1 : { Andor = new Citrom(param1, param2, param3); }
      case 2 : { Andor = new Blabla(param1,param4,param5); }
      etc.
      }
    Est-il possible de g�n�raliser ces multiples initialisations sous une forme plus �l�gante plut�t que d'avoir une liste de if/else en fonction d'un param�tre 'une variable' sans pour autant alt�rer la performance (en termes de temps de calcul) de l'ensemble ? Je ne vois pas de solution magique, mais j�admets que ma connaissance du langage est plut�t limit�.

    Merci!

  2. #2
    Expert confirm�
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    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 772
    Par d�faut
    Cela ressemble furieusement au patron de conception fabrique/ usine (<- lien wikipedia en anglais)

    lien developpez

    Les 2 liens utilisent 1 tableau associatif pour stocker 1 couple objet/ clef "cha�ne de caract�res"

    Je voyais + comme celle ci sur cette page : on va mettre ton if/ else dans 1 m�thode create.
    C'est du code C++11 avec des std::unique_ptr.
    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
    68
    69
    70
    71
    72
    73
    74
    75
    #include<iostream>
    #include<memory>
     
    //Pizza
    class Pizza {
    public:
        virtual void BakePizza()=0; 
        virtual void PackPizza()=0;
    };
     
    class DominoPanerrPiza : public Pizza {
    public:
        void BakePizza() {
            std::cout<<"DominoPanerrPiza is ready"<<std::endl;
        }
        void PackPizza() {
            std::cout<<"DominoPanerrPiza is packed"<<std::endl;
        }
    };
     
    class DominoCheesePiza : public Pizza {
    public:
        void BakePizza() {
            std::cout<<"DominoCheesePiza is ready"<<std::endl;
        }
        void PackPizza() {
            std::cout<<"DominoCheesePiza is packed"<<std::endl;
        }
    };
     
    //class PizzaFactory
    class PizzaFactory {
    protected:
        std::unique_ptr<Pizza> _mPizza;
    public:
        Pizza* GetPizza(std::string type) {  
            _mPizza.reset(CreatePizza(type));
            return _mPizza.release();     
        }
    private:
        virtual Pizza* CreatePizza(std::string type)=0;
    };
     
    //DominoPizzaFactory
    class DominoPizzaFactory: public PizzaFactory {
    private:
        Pizza* CreatePizza(std::string type) {
            Pizza* pz = nullptr;
            if(type == "Paneer")
                pz = new DominoPanerrPiza;
            else if (type == "Cheese")
                pz = new DominoCheesePiza;
            else
                nullptr;
     
            return  pz;
        }
    };
     
    //Client
    int main()
    {
        std::cout<<"In Main"<<std::endl;
        //Select Factory
        std::unique_ptr<PizzaFactory>ptr{nullptr};
        ptr.reset(new DominoPizzaFactory);
        //Order the Pizza with type
        std::cout<<"Ordering Paneer Pizza from Domino"<<std::endl;
        std::unique_ptr<Pizza>upPz{nullptr};
        upPz.reset(ptr->GetPizza("Paneer"));
        upPz->BakePizza();
        upPz->PackPizza();
        std::cout<<"!!!!!!!!!!Got the Pizza!!!!!!!!!"<<std::endl;
        return 0;
    }
    Ou encore comme celle ci : on va surcharger autant d'usines que de types et ensuite, c'est au client d'utiliser soit la bonne usine surcharg�e soit le polymorphisme (ici injection de d�pendances)
    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
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    /**
     * The Product interface declares the operations that all concrete products must
     * implement.
     */
    class Product {
     public:
      virtual ~Product() {}
      virtual std::string Operation() const = 0;
    };
     
    /**
     * Concrete Products provide various implementations of the Product interface.
     */
    class ConcreteProduct1 : public Product {
     public:
      std::string Operation() const override {
        return "{Result of the ConcreteProduct1}";
      }
    };
     
    class ConcreteProduct2 : public Product {
     public:
      std::string Operation() const override {
        return "{Result of the ConcreteProduct2}";
      }
    };
     
    /**
     * The Creator class declares the factory method that is supposed to return an
     * object of a Product class. The Creator's subclasses usually provide the
     * implementation of this method.
     */
    class Creator {
      /**
       * Note that the Creator may also provide some default implementation of the
       * factory method.
       */
     public:
      virtual ~Creator(){};
      virtual Product* FactoryMethod() const = 0;
     
      /**
       * Also note that, despite its name, the Creator's primary responsibility is
       * not creating products. Usually, it contains some core business logic that
       * relies on Product objects, returned by the factory method. Subclasses can
       * indirectly change that business logic by overriding the factory method and
       * returning a different type of product from it.
       */
     
      std::string SomeOperation() const {
        // Call the factory method to create a Product object.
        Product* product = this->FactoryMethod();
        // Now, use the product.
        std::string result = "Creator: The same creator's code has just worked with " + product->Operation();
        delete product;
        return result;
      }
    };
     
    /**
     * Concrete Creators override the factory method in order to change the
     * resulting product's type.
     */
    class ConcreteCreator1 : public Creator {
      /**
       * Note that the signature of the method still uses the abstract product type,
       * even though the concrete product is actually returned from the method. This
       * way the Creator can stay independent of concrete product classes.
       */
     public:
      Product* FactoryMethod() const override {
        return new ConcreteProduct1();
      }
    };
     
    class ConcreteCreator2 : public Creator {
     public:
      Product* FactoryMethod() const override {
        return new ConcreteProduct2();
      }
    };
     
    /**
     * The client code works with an instance of a concrete creator, albeit through
     * its base interface. As long as the client keeps working with the creator via
     * the base interface, you can pass it any creator's subclass.
     */
    void ClientCode(const Creator& creator) {
      // ...
      std::cout << "Client: I'm not aware of the creator's class, but it still works.\n"
                << creator.SomeOperation() << std::endl;
      // ...
    }
     
    /**
     * The Application picks a creator's type depending on the configuration or
     * environment.
     */
    int main() {
      std::cout << "App: Launched with the ConcreteCreator1.\n";
      Creator* creator = new ConcreteCreator1();
      ClientCode(*creator);
      std::cout << std::endl;
      std::cout << "App: Launched with the ConcreteCreator2.\n";
      Creator* creator2 = new ConcreteCreator2();
      ClientCode(*creator2);
     
      delete creator;
      delete creator2;
      return 0;
    }

    �dit: Apr�s pour les diff�rents types de param�tres pour le constructeur c'est vrai que cela pose probl�me
    Mais, dans 1 premier temps, on peut utiliser 1 usine avec donc des "lazy constructors". Et ensuite, dans chaque type concret, faire 1 m�thode d'initialisation init (*) avec 1 DTO (1 structure par exemple) qui contient TOUS les param�tres (c'est (*) qui choisira quels param�tres lui convient)

    C'est d'ailleurs 1 peu la r�ponse de ton sujet Stack Overflow (qui parle de boost::variant, qui est 1 union), et qui met 1 bool�en par param�tre pour savoir si la "classe m�re" peut utiliser tel ou tel param�tre d'1 classe fille concr�te.

  3. #3
    Membre confirm�
    Inscrit en
    F�vrier 2013
    Messages
    94
    D�tails du profil
    Informations forums :
    Inscription : F�vrier 2013
    Messages : 94
    Par d�faut
    Bonjour,
    Tout d'abord merci pour ce retour rapide!
    Les liens correspondent exactement � ma question, je ne connaissais pas du tout cette architecture de factory/fabrique, c'est vraiment int�ressant!
    Effectivement j'ai mis des constructeurs diff�rents pour les classes filles, en me disant que ce cas l� pouvait se produire aussi, rajoutant de la complexit� � l'ensemble. Je vois l'�dit et je me pose une autre question, plus li�e � la performance (en termes de running-time du code): si on passe tous les param�tres lors de l'initialisation et qu'on imagine que ces classes sont initialis�s dans un thread, ca ne risque pas de ralentir l'ensemble? Autrement dit, passer tous les param�tres qui peuvent �tre des objets "complexes"/lourds vs. la liste n�cessaire � la construction de chaque fille ?

    Merci pour les informations!

  4. #4
    Expert �minent
    Avatar de M�dinoc
    Homme Profil pro
    D�veloppeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par d�faut
    Pour l'instant, il n'est pas de question de multithreading ici: Tout se fait dans le thread courant.

    Apr�s, un exemple plus complexe consisterait � se passer des switch compl�tement:
    Code C++ : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    std::map<std::string, std::unique_ptr<IPizzaFactory>> factories;
    factories["Domino"] = make_unique<DominoPizzaFactory>();
    factories["PizzaDelArte"] = make_unique<PizzaDelArteFactory>();
     
    ...
     
    UniversalPizzaRequest whatIWant {};
    factories["Domino"]->CreatePizza(whatIWant);
    On peut m�me envisager que les factories soient impl�ment�es dans des DLLs, et list�es dans un fichier de configuration.
    Ou encore, de choisir la factory non pas via son nom, mais ces capacit�s (genre chaque factory supporte une certaine liste de toppings, la requ�te contient elle aussi une liste, et une fonction de recherche retournerait la premi�re factory trouv�e qui supporte tous les toppings de la requ�te).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parl� avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Expert confirm�
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    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 772
    Par d�faut
    Si c'est 1 question de "threads", il faut donc tester : en l'�tat impossible de dire quoi ce soit

    Mais les DTO (Data Transfer Object) sont justement utilis�s pour transmettre des donn�es (0 logique) (il ne restent pas ""en m�moire"")
    En C++, 1 structure est 1 classe publique, et donc b�n�ficie des constructeur/ destructeur.

    Ensuite pour la taille, tu mets des pointeurs ("smart "ou "raw") dans tes DTO. Si ce sont de gros objets, il faut les cr�er � 1 moment ou 1 autre et donc appeler "1 constructeur" et donc pointeur
    1 pointeur c'est 8 octets (64 bits) ce n'est pas grand chose.
    Tu as aussi les union qui permettent d'optimiser et de s�parer les diff�rentes "combinaisons" de param�tres (la taille d'1 union, c'est la taille de la plus grosse "donn�e").

  6. #6
    Membre confirm�
    Inscrit en
    F�vrier 2013
    Messages
    94
    D�tails du profil
    Informations forums :
    Inscription : F�vrier 2013
    Messages : 94
    Par d�faut
    Merci � tous pour ces r�ponses �clairantes!
    Je marque comme r�solu

+ R�pondre � la discussion
Cette discussion est r�solue.

Discussions similaires

  1. Les design pattern pour cr�er des jeux
    Par alex6891 dans le forum Design Patterns
    R�ponses: 4
    Dernier message: 26/11/2018, 19h59
  2. R�ponses: 4
    Dernier message: 06/03/2008, 10h22
  3. [2.0] polymorphisme avec des types g�n�rique
    Par mister3957 dans le forum G�n�ral Dotnet
    R�ponses: 3
    Dernier message: 31/05/2007, 08h11
  4. Problème de formulaire avec des If-Else
    Par MasterChief78 dans le forum Access
    R�ponses: 21
    Dernier message: 29/08/2006, 12h54

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