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 :

[Conception] Metaclass-Regles parametrees


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut [Conception] Metaclass-Regles parametrees
    Bonjour,

    J'ai un gros problème de conception. Je le met dans C++ car je dois le résoudre en C++.

    J'ai des regles types, appelées RulesType qui ont comme propriétés:
    - un ID
    - un Nom
    - Des parametres Generiques(liste de parametres possibles)
    - Un resultat generiques (liste de resultat possible)
    - L'action de la règle en fonction des parametres et du resultat

    A partir de ces RulesType j'ai des Rules qui ont comme propriétés:
    - Un ID
    - un Nom
    - Des parametres spécifiques(pris parmis les resultats generiques de RulesType


    Chaque Rules dépend d'un RulesType. Je peux avoir n Rules par RulesType.
    Et je peux avoir m RulesType différents avec des parametres differents et des resultats differents.
    De plus, il me faut un RulesManager qui gerent l'ensemble de mes RulesType (pour les lister en fait).
    Il faut que je puisse instancier des Rules en fonction des RulesType associés (en gros mettre les bons parametres).

    Ou j'en suis:
    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
    // RuleTest.cpp : Defines the entry point for the console application.
    //
     
    #include <iostream>
    #include <map>
    #include <string>
    #include "stdafx.h"
     
    class RuleType{
    public:
        RuleType(int anId, std::string aName): id (anId), name (aName) {}
    protected:
        int id;
        std::string name;
     
    protected:
        RuleType();
        static std::map< int, RuleType*> rules;
     
    public:
        virtual int getID() {return id;}
        virtual std::string getName() {return name;}
        static void insertRule(int i, RuleType* rule) {rules[i] = rule;}
        static RuleType * getRule(int i) {return rules[i];}
    };
     
    std::map<int, RuleType*> RuleType::rules;
     
     
    class Rule1: public RuleType{
    public:
        Rule1(int anId, std::string aName): RuleType(anId, aName) {}
     
    private:
        Rule1();
        int idRule;
     
    public:
        int performRule(int i) {return i;}
    };
     
    class Rule2: public RuleType{
    public:
        Rule2(int anId, std::string aName): RuleType(anId, aName) {}
     
    private:
        Rule2();
        int idRule;
     
    public:
        std::string performRule(std::string str) {return str;}
    };
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        Rule1 * rule1 = new Rule1(1, "Rule1");
        Rule2 * rule2 = new Rule2(2, "Rule2");
        RuleType::insertRule(rule1->getID(), rule1);
        RuleType::insertRule(rule2->getID(), rule2);
     
        Rule1 * ruletmp1 = static_cast< Rule1 * > (RuleType::getRule(1));
        std::cout << "Rule1: " << ruletmp1->performRule(1) << std::endl;
     
        Rule2 * ruletmp2 = static_cast< Rule2 * > (RuleType::getRule(2));
        std::cout << "Rule2: " << ruletmp2->performRule("Rule2") << std::endl;
     
        int i;
        std::cin >> i;
    	return 0;
    }
    La class RuleManager est a la fois mon RuleManager et définit les parametres de base d'une Rules.
    Rule1 et Rule2 sont des RulesType differents (leur fonction performRule est differentes)
    Mon probleme est que je dois faire un static_cast et je trouve pas ca très beau.


    Des idées?

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Ce que je ferais, c'est créer une classe abstraite - nommons la "Parametre" pour la cause - qui s'occupe simplement de gérer... les paramètres.

    Elle ressemblerait à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Parametre
    {
        public:
            Parametre(Parametre * n=0);
            virtual ~Parametre();
            Parametre* next(){return m_next;}
            virtual bool evaluate() =0 const; /* le type de retrour est à réfléchir... 
                                               * un retour  co-variant pourrait être le 
                                               * bienvenu :D
                                                */
        private:
            Parametre* m_next;
    };
    Elle serait implémentée sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Parametre::Parametre(Parametre * n): m_next(n)
    {
    }
    Parametre::~Parametre()
    {
    }
    Si tu veux en restreindre l'usage, rien ne t'empêche d'en faire une classe imbriquée dans ta classe RuleType .

    Tu pourrais alors faire dériver cette classe en différents paramètres concrets qui implémenteraient la méthode virtuelle pure evaluate (on va dire, pour les besoins de l'exemple, que tu la fait dériver en P1, P2 et P3 ).

    Ta classe RuleType prendrait alors la forme de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class RuleType
    {
        public:
            RuleType(size_t, const std::string&, Parametre* p=0
            /*éventuellement */ RuleType* next=0);
            ~RuleType();
            bool isVerified() const; /* ici aussi, on peut réfléchir à un autre type
                                      * de retour ;)
                                      */
            size_t id() const{return m_id;}
            const std::string& name() const {return m_name;}
            /*si une regle doit pouvoir appeler une autre règle */
            RuleType* nextRule(){return m_next;}
            void setNextRule(RuleType* n){m_next=n;}
        private:
            size_t m_id;
            std::string m_name;
            Parametre* m_p;
            /*si une regle doit pouvoir appeler une autre règle */
            RuleType* m_next;
    };
    et l'implémentation des méthodes serait de l'ordre de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    RuleType::RuleType(const sd::string& i, const std::string& n, Parametre* p)
             :m_id(i),m_name(n),m_p(p),m_next(0)
    {
    }
    RuleType::~RuleType()
    {
        /*chaque règle est responsable de la destruction de ses paramètres*/
     
        while(m_p)
        {
            Param* t=m_p->next();
            delete m_p;
            m_p=t;
        }
        /* mais, par contre, ce sera au RuleManager de s'occuper de la 
         * destructions des règles, y compris de celle qui doit suivre :D
         */
    }
    bool RuleType::isVerified() const
    {
        /* on commence par déterminer si la regle est suivie en fonction
         * de ses parametres... par défaut, nous considérerons que c'est le cas
         */
        bool ret= true;
        Parametre * tmp=m_p;
        while(tmp && ret)
        {
            /* si un parametre n'est pas correctement évalué, la règle n'est
             * pas respectée :D
             */
            ret=ret&tmp->evaluate();
            ret=ret->next();
        }
        /*reste à savoir si une regle suit celle-ci, et à l'évaluer,si c'est
         * nécessaire je considère ici qu'il est inutile d'évaluer la règle
         * suivante si celle en cours n'est pas vérifiée :D
         */
        if(ret && m_next)
            return ret&m_next->isVerified();
        return ret;
    }
    Tu sera au final en mesure de créer une règle sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    RuleType r(1,"LaRegle", new P1("lavaleur de p1", 
                            new P2 (1836, 
                            new P3(3.1415926)));
    en étant libre du nombre de paramètre à lui passer

    Quand tu veux voir si une règle est vérifiée au départ de ton RuleManager, il te "suffira" de sélectionner la règle en question, et d'invoquer dessus la méthode isVerified() pour que tous les paramètres (et les règles "suivantes" s'il y en a et si tu a décidé que cela pouvait se faire) soient évaluées

    [EDIT]code de Parametre édité
    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 confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut
    Merci de ta reponse. Mais malheureusement c'est un poil plus compliqué.

    virtual bool evaluate() =0 const;
    *je ne peux pas faire ca, car evaluate prend differents parametres suivant le "Type" de parametre et peut avoir des types de retour differents.

    Le code est pas super propre vu que je fais mes tests, mais c'est l'idée.
    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
    class Parameter{
    public:
        Parameter(std::string aName, int idOp): name (aName), idOperator (idOp) {}
    protected:
        Parameter()  {}
        std::string name;
        int idOperator;
     
     
    public:
        std::string getName() {return name;}
    };
     
    enum ParameterIntOperators{
        equal,
        less,
        more
    };
     
    class ParameterInt: public Parameter {
    public:
        ParameterInt(std::string aName, int idOp, int anIdValue): Parameter(aName, idOp), idValue (anIdValue) {}
     
        bool getResult(int number) {
            if (idOperator == equal) {return number == idValue;}
            if (idOperator == less) {return number < idValue;}
            if (idOperator == more) {return number > idValue;}
            return false;
        }
    private:
            int idValue;
    };
     
    enum ParameterBenchOperators{
        bench,
        Hmin
    };
     
    class ParameterBench: public Parameter {
    public:
        ParameterBench(std::string aName, int idOp, int anIdValue): Parameter(aName, idOp), idValue (anIdValue) {}
     
        int getResult(int bench, int pos, int hmin = 0, int Hmax = 0, int Hr = 0) {
            if (idOperator == bench) {return bench + pos;}
            if (idOperator == Hmin) {return hmin + Hmax + Hr;}
            return 0;
        }
    private:
            int idValue;
    };
     
    enum ParameterStringOperators{
        toto,
        tata
    };
     
    class ParameterString: public Parameter {
    public:
        ParameterString(std::string aName, int idOp, std::string anIdValue): Parameter(aName, idOp), idValue (anIdValue) {}
     
        std::string getResult(std::string exemple) {
            if (idOperator == toto) {return exemple + idValue;}
            if (idOperator == tata) {return exemple + "tata" +idValue;}
            return "";
        }
    private:
        std::string idValue;
     
    };

    Ensuite une regle ne peut suivre une regle, elles sont toutes independantes les une des autres pour l execution.
    Mes regles me permettent en fait de faire des calculs precis, une regle pouvant me retourner une date, une autre pouvant me retourner un entier, une autre une chaine de caractere.
    En gros je dois melanger du lard et du cochon dans une structure coherente

    mon code entier pour l instant:
    Il represente bien ce que je veux faire. Les deux fonctions qui me posent problemes et qui m obligent a faire des choses pas bien sont getResult(..) des classes Parameter et performRule(..) des class Rule.

    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
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    // RuleTest.cpp : Defines the entry point for the console application.
    //
     
    #include <iostream>
    #include <map>
    #include <string>
    #include "stdafx.h"// RuleTest.cpp : Defines the entry point for the console application.
     
    class Parameter{
    public:
        Parameter(std::string aName, int idOp, int anIdValue): name (aName), idOperator (idOp), idValue (anIdValue) {}
    protected:
        Parameter()  {}
        std::string name;
        int idOperator;
        int idValue;
     
    public:
        std::string getName() {return name;}
    };
     
    enum ParameterIntOperators{
        equal,
        less,
        more
    };
     
    class ParameterInt: public Parameter {
    public:
        ParameterInt(std::string aName, int idOp, int anIdValue): Parameter(aName, idOp, anIdValue) {}
     
        bool getResult(int number) {
            if (idOperator == equal) {return number == idValue;}
            if (idOperator == less) {return number < idValue;}
            if (idOperator == more) {return number > idValue;}
            return false;
        }
    };
     
    enum ParameterBenchOperators{
        bench,
        Hmin
    };
     
    class ParameterBench: public Parameter {
    public:
        ParameterBench(std::string aName, int idOp, int anIdValue): Parameter(aName, idOp, anIdValue) {}
     
        int getResult(int bench, int posOam, int hmin = 0, int Hmax = 0, int Hr = 0) {
            if (idOperator == bench) {return bench + posOam;}
            if (idOperator == Hmin) {return hmin + Hmax + Hr;}
            return 0;
        }
     
     
    };
     
    class RuleManager{
    public:
        RuleManager(int anId, std::string aName): id (anId), name (aName) {}
    protected:
        int id;
        std::string name;
        std::map < int, Parameter* > parameters;
     
    protected:
        RuleManager();
        static std::map< int, RuleManager*> rules;
     
    public:
        virtual int             getID()                                 {return id;}
        virtual std::string     getName()                               {return name;}
        virtual void            insertParam(int i, Parameter* param)    {parameters[i] = param;}
        virtual Parameter*      getParam(int i)                         {return parameters[i];}
        static void             insertRule(int i, RuleManager* rule)    {rules[i] = rule;}
        static RuleManager *    getRule(int i)                          {return rules[i];}
    };
     
    std::map<int, RuleManager*> RuleManager::rules;
     
    class Rule1: public RuleManager{
    public:
        Rule1(int anId, std::string aName): RuleManager(anId, aName) {}
     
    private:
        Rule1();
        int idRule;
     
    public:
        int performRule(int i) {
            int res = i;
            int bench_ = 10;
            int posOam_ = 15;
            int hmin_ = 5;
            int hmax_ = 6;
            if (static_cast<ParameterInt*>(getParam(1))->getResult(bench_)) {
                res += 10;
            }
            if (static_cast<ParameterInt*>(getParam(2))->getResult(bench_)) {
                res += 10;
            }
            res += static_cast<ParameterBench*>(getParam(3))->getResult(bench_, posOam_);
            return res;
        }
    };
     
    class Rule2: public RuleManager{
    public:
        Rule2(int anId, std::string aName): RuleManager(anId, aName) {}
     
    private:
        Rule2();
        int idRule;
     
    public:
        std::string performRule(std::string str) {return str;}
    };
     
    int _tmain(int argc, _TCHAR* argv[])
    {
        Rule1 * rule1 = new Rule1(1, "Rule1");
        Rule2 * rule2 = new Rule2(2, "Rule2");
        RuleManager::insertRule(rule1->getID(), rule1);
        RuleManager::insertRule(rule2->getID(), rule2);
        rule1->insertParam(1, new ParameterInt("int", equal, 10));
        rule1->insertParam(2, new ParameterInt("int", less, 15));
        rule1->insertParam(3, new ParameterBench("bench", bench, 20));
     
        Rule1 * ruletmp1 = static_cast< Rule1 * > (RuleManager::getRule(1));
        std::cout << "Rule1: " << ruletmp1->performRule(1) << std::endl;
     
        Rule2 * ruletmp2 = static_cast< Rule2 * > (RuleManager::getRule(2));
        std::cout << "Rule2: " << ruletmp2->performRule("Rule2") << std::endl;
     
        int i;
        std::cin >> i;
        return 0;
    }
    PS: je sais, la gestion de la memoire est inexistante, mais bon c'est des tests, donc jai la flemme de tout faire bien et propre.

    Merci de ton aide en tout cas.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par escafr Voir le message
    Merci de ta reponse. Mais malheureusement c'est un poil plus compliqué.


    *je ne peux pas faire ca, car evaluate prend differents parametres suivant le "Type" de parametre et peut avoir des types de retour differents.
    Comme je l'ai indiqué dans le code, tu peux sans doute envisager un retour co-variant pour evaluate... Cela nécessite évidemment d'avoir une arborescence de "retour" cohérente, avec un interface permettant le polymorphisme dessus

    Ici, l'idée est de se dire "j'évalue un parametre, et je renvoi le résultat correspondant au type de paramètre évalué"

    Rien ne t'interdit non plus de rajouter des méthodes "qui vont bien", voire, de prévoir une surcharge pour la méthode évaluate

    L'idée étant qu'un parametre donné ne soit responsable que d'une chose: son
    <snip>
    Ensuite une règle ne peut suivre une regle, elles sont toutes independantes les une des autres pour l execution.
    comme indiqué dans les commentaires (il faut toujours lire les commentaires, je les met pour indiquer les variantes envisageable), je ne t'indiquais qu'une optique possible...

    Libre à toi de supprimer toute référence à "une règle suivante" dans le code
    Mes regles me permettent en fait de faire des calculs precis, une regle pouvant me retourner une date, une autre pouvant me retourner un entier, une autre une chaine de caractere.
    En gros je dois melanger du lard et du cochon dans une structure coherente
    Et alors, ou est le problème
    tu crée une interface pour "les parametres" et une interface pour "le type de calcul"

    En rendant la méthode isVerified(), nommée ainsi parce que, pour moi une règle est plutot le genre de truc pour lequel on répond à la question "la règle est-elle suivie", mais que l'on pourrait très bien nommer calculate() virtuelle, rien ne t'empeche de créer une arborescence sur base de cette classe...

    Tu as donc deux arborescences bien distinctes dont l'une te permet de dire "je veux faire ceci", et l'autre te permet de dire "et voila avec quoi je veux le faire"

    Ca pourrait tout aussi bien prendre une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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
     
    class Operation
    {
        public:
            Operation(Operation* n =0):m_next(0){}
            virtual ~Operation(){}
            Operation* next() {return m_next;}
            virtual double calculate(double) =0;
            /* à n'utiliser que pour les classes dérivant de Calcul */
            void setNext(n){m_next=n;}
        private:
            Operation * m_next;
    };
    /* chaque opération contient l'opérande se trouvant à droite du signe */
    class Add:public Operation
    {
        public:
            Add(double rval, Operation* n = 0):Operation(n), m_val(rval){}
            virtual ~Add(){}
            virtual double calculate(double lval)
            {return lval+m_val;}
        private:
            double m_val;
    };
    class Multiply:public Operation
    {
        public:
            Multiply(double rval, Operation* n = 0):Operation(n), m_val(rval){}
            virtual ~Multiply();
            virtual double calculate(double lval)
            {return lval*m_val;}
        private:
            double m_val;
    };
    class Substract:public Operation
    {
        public:
            Substract(double rval, Operation* n = 0):Operation(n), m_val(rval){}
            virtual ~Substract();
            virtual double calculate(double lval)
            {return lval-m_val;}
        private:
            double m_val;
    };
    class Divide:public Operation
    {
        public:
            Divide(double rval, Operation* n = 0):Operation(n), m_val(rval){}
            virtual ~Substract();
            virtual double calculate(double lval)
            {   
                 /*idéalement, il faudrait sortir une erreur si division par 0 ;) */
                 return lval/m_val;
            }
        private:
            double m_val;
    };
    et, tu aurais dune classe "Calcul" qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    class Calcul
    {
        public: 
            Calcul(double first, Operation* op= 0):m_first(first), m_op(op){}
            ~Calcul(){/*suppression des opérations ;) */}
            virtual double evaluate() const;
            {
                 double ret=m_first;
                 Operation* temp=m_op;
                 while(temp)
                 {
                     temp->calculate(ret);
                     temp=temp->next;
                 }
                 return ret;
            }
        protected:
            Operation m_op;
        private:
            double m_first;
    };
    Bon, bien sur, j'ai passé les id, les nom et d'autres trucs, inutiles à ma démonstration...
    Mais tu pourrais très bien alors envisager de la dériver en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class TwoOpsCalcul : public Calcul
    {
        public:
            TwoOpsCalcul(double first, Operation* fop, Operation* sop)
                Calcul(first, fop)
            {
                assert(fop!=0);
                assert(sop!=0);
                fop->setNext(sop);
            }
            virtual ~TwoOpsCalcul(){}
     
    }
    qui te permettra de créer un calcul du genre de 2+4*5 (et tu peux t'amuser à créer autan de classe que tu veux avec autant d'opérations que tu veux sur le même principe )
    mon code entier pour l instant:
    Il represente bien ce que je veux faire. Les deux fonctions qui me posent problemes et qui m obligent a faire des choses pas bien sont getResult(..) des classes Parameter et performRule(..) des class Rule.[/QUOTE]
    La méthode performRule, c'est en fait la méthode evaluate présentée plus haut

    Maintenant, il est peut etre utile de prévoir une classe Resultat, que tu ferai dériver en plusieurs autres classe, afin de permettre le retour co-variant

    Une des idées principales en Orienté objet, c'est la délégation des responsabilités: Si une de tes classe est responsable de plus d'une chose, c'est sans doute qu'elle a trop de responsabilités:

    Ici, tu as quatre responsabilités distinctes déjà identifiées, qui portent respectivement sur
    • le résultat
    • l'opération
    • le calcul
    • la gestion des calculs


    Tu dois donc avoir au minimum 4 classes: une pour chacune de ces responsabilités.

    Pour trois d'entre-elles, (le résultat, l'opération et le calcul), tu dois sans doute envisager un arbre d'héritage séparé (un calcul n'a rien à voir avec les différents types d'opération qu'il doit effectuer, une opération n'a rien à voir avec les différents type de résultat qu'il doit obtenir), de manière à pouvoir profiter au mieux du polymorphisme et du retour co-variant en cas de besoin.

    De cette manière, si un jour tu te rend compte qu'il faut un nouveau type de résultat, tu pourra te contenter de le créer sans devoir aller modifier le code des opérations.

    Par contre, il est fort vraisemblable que tu doive aussi (parce que c'est sans doute la raison pour laquelle ce nouveau type de résultat est nécessaire), créer une nouveau type d'opération, voire, un nouveau type de calcul...

    Mais l'avantage résidera dans le fait que tous les type d'opération et tous les types de calcul existants ne devront absolument pas être modifiés

    Le diagrame UML de ton ensemble ressemblerait à celui ci-joint (fait en quatrième vitesse )

    Ainsi, Resultat s'occupera de gérer le type et la valeur du résultat d'une opération, une opération se contentera de créer le résultat attendu, un calcul s'occupera d'appeler les différentes opérations nécessaires (bien qu'il renvoie lui aussi un résultat), et le RuleManager s'occupera de gérer les différents calculs que l'on peut lui demander
    <sniped code>

    PS: je sais, la gestion de la memoire est inexistante, mais bon c'est des tests, donc jai la flemme de tout faire bien et propre.
    Ca, c'est vraiment pas bien ...

    Même pour des essais, il faut veiller à ce que ton code soit correct
    Images attachées Images attachées  
    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

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut
    ouah.. j'en demandais pas autant. Merci..

    Alors le retour covariant je connaissais pas du tout. C'est plutot sympa dans l'esprit mais je pense que c'est un poil trop compliquer les choses.

    Après réflexion, et discussion avec un collègue, je vais m'orienter vers une solution bcp plus simple

    En fait le problème fondamental que j'avais, était de dissocier la description de mes regles de l'utilisation de mes regles. De meme pour mes parametres.
    L'idée est donc de dissocier les deux.
    Une regle type contient une description de regle et une description de parametre.
    Une regle contient des parametres. Je parametre mes regles en fonction de leur description. Simple efficace.

    Je reviendrai avec la facon d'implementer tout ca bientot

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2003
    Messages : 224
    Par défaut
    Bonsoir,

    Me revoila avec une interogation sur le retour covariant


    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
    class Rule{
    protected:
        Rule() {ruleDesc = NULL;}
    public:
        Rule(RuleDescription* ruleDesc):  ruleDesc(ruleDesc) {}
        virtual ~Rule(){
            while (!paramDesc.empty()){
                delete paramDesc.begin()->second;
                paramDesc.erase(paramDesc.begin());
            }
        }
    
        void insertParam(int i, ParameterDescription* param) {paramDesc[i] = param;}
    
        int getNumberParam() {return paramDesc.size();}
        std::string getNameParam(int i) {return paramDesc[i]->getName();}
        int getOperatorParam(int i) {return paramDesc[i]->getOperator();}
        std::string getOperatorValue(int i) {return paramDesc[i]->getValue();}
    
        void print() {
            std::cout << "Listing Params for rule:" << ruleDesc->getName() << std::endl;
            for(std::map <int, ParameterDescription*>::const_iterator i = paramDesc.begin(); i != paramDesc.end(); i++){
                i->second->print();
            }
            std::cout << "----" << std::endl;
        }
        virtual int getScope(int i) = 0;
        virtual Rule* getRule(int i)  = 0;
    
    protected:
        RuleDescription* ruleDesc;
        std::map <int, ParameterDescription*> paramDesc;
    
    };
    
    class RuleBackToBench: public Rule{
    public:
        RuleBackToBench( RuleDescription* ruleDesc): Rule( ruleDesc) {}
    
        static RuleBackToBench* getRule(int i) {
            std::stringstream strname;
            std::stringstream strdate;
            // Recherche Scope et recuperation bon RuleDescription
            RuleBackToBench* ruleB = new RuleBackToBench(RuleDescription::getRule(getScope(i)));
            for (int i = 0; i < 5; i++){
                ParameterDescription* tmp = NULL;
                strname.str("");
                strdate.str("");
                strname << "NameParam" << i;
                strdate << "Value" << i;
                tmp = new ParameterDescription(i, strname.str(), i%2, strdate.str());
                ruleB->insertParam(i, tmp);
            }
            return ruleB;
        }
    
        static int getScope(int i) {return i;}
    };
    
    class RuleSettlement: public Rule{
    public:
        RuleSettlement( RuleDescription* ruleDesc): Rule( ruleDesc) {}
    
        static RuleSettlement* getRule(int i) {
            std::stringstream strname;
            std::stringstream strdate;
            // Recherche Scope et recuperation bon RuleDescription
            RuleSettlement* ruleB = new RuleSettlement(RuleDescription::getRule(getScope(i)));
            for (int i = 0; i < 5; i++){
                ParameterDescription* tmp = NULL;
                strname.str("");
                strdate.str("");
                strname << "NameParam" << i;
                strdate << "Value" << i;
                tmp = new ParameterDescription(i, strname.str(), i%2, strdate.str());
                ruleB->insertParam(i, tmp);
            }
            return ruleB;
        }
    
        static int getScope(int i) {return i;}
    };

    faisant partie du code plus vaste:
    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
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    // RuleTest2.cpp : Defines the entry point for the console application.
    //
     
    #include "stdafx.h"
    #include <string>
    #include <iostream>
    #include <sstream>
    #include <map>
     
    class Rule;
     
    class RuleTypeDescription{
    private:
        RuleTypeDescription();
    public:
        RuleTypeDescription(int id, std::string name, int nature, std::string creaDate, std::string doc): id(id), name(name), nature(nature),creaDate(creaDate), doc(doc) {}
     
        static void insertDesc(int i, RuleTypeDescription* obj) {rulesTypeDesc[i] = obj;}
     
        int getNature() {return nature;}
    private:
        int id;
        std::string name;
        int nature;
        std::string creaDate;
        std::string doc;
     
        static std::map <int, RuleTypeDescription*> rulesTypeDesc;
     
    public:
        void printRule() const{
            std::cout << id << ":" << name << ":" << nature << ":" << creaDate << doc << std::endl;
        }
     
        static void listRules() {
            std::cout << "Listing RuleType:" << std::endl;
            for(std::map <int, RuleTypeDescription*>::const_iterator i = rulesTypeDesc.begin(); i != rulesTypeDesc.end(); i++){
                i->second->printRule();
            }
            std::cout << "----" << std::endl;
        }
        static void kill() {
            while (!rulesTypeDesc.empty()){
                delete rulesTypeDesc.begin()->second;
                rulesTypeDesc.erase(rulesTypeDesc.begin());
            }
        }
        static RuleTypeDescription* getRuleType(int i) {return rulesTypeDesc[i];}
    };
     
    std::map <int, RuleTypeDescription*> RuleTypeDescription::rulesTypeDesc;
     
     
    class RuleDescription{
    private:
        RuleDescription();
    public:
        RuleDescription(int id, std::string name, std::string scope, RuleTypeDescription * ruleType): id(id), name(name), scope(scope),ruleType(ruleType)  {}
     
        static void insertDesc(int i, RuleDescription* obj) {rulesDesc[i] = obj;}
     
        std::string getName() {return name;}
    private:
        int id;
        std::string name;
        std::string scope;
        std::string creaDate;
        std::string startDate;
        std::string endDate;
        std::string user;
     
        RuleTypeDescription * ruleType;
     
        static std::map <int, RuleDescription*> rulesDesc;
     
    public:
        void printRule() const {
            std::cout << id << ":" << name << ":" << ruleType->getNature() << ":" << scope << ":" << creaDate << std::endl;
        }
     
        static void listRules() {
            std::cout << "Listing Rules:" << std::endl;
            for(std::map <int, RuleDescription*>::const_iterator i = rulesDesc.begin(); i != rulesDesc.end(); i++){
                i->second->printRule();
            }
            std::cout << "----" << std::endl;
        }
        static void kill() {
            while (!rulesDesc.empty()){
                delete rulesDesc.begin()->second;
                rulesDesc.erase(rulesDesc.begin());
            }
        }
     
        static RuleDescription* getRule(int i) {return rulesDesc[i];}
    };
     
    std::map <int, RuleDescription*> RuleDescription::rulesDesc;
     
    class ParameterDescription{
    public:
        ParameterDescription(int id, std::string name, int op, std::string value): id (id), name (name), idoperator(op), value(value) {}
     
    private:
        ParameterDescription();
        int id;
        std::string name;
     
        int idoperator;
        std::string value;
    public:
        std::string getName() {return name;}
        int getOperator() {return idoperator;}
        std::string getValue() {return value;}
     
        void print() {std::cout << name << ":" << idoperator << ":" << value << std::endl;}
     
    };
     
    class Rule{
    protected:
        Rule() {ruleDesc = NULL;}
    public:
        Rule(RuleDescription* ruleDesc):  ruleDesc(ruleDesc) {}
        virtual ~Rule(){
            while (!paramDesc.empty()){
                delete paramDesc.begin()->second;
                paramDesc.erase(paramDesc.begin());
            }
        }
     
        void insertParam(int i, ParameterDescription* param) {paramDesc[i] = param;}
     
        int getNumberParam() {return paramDesc.size();}
        std::string getNameParam(int i) {return paramDesc[i]->getName();}
        int getOperatorParam(int i) {return paramDesc[i]->getOperator();}
        std::string getOperatorValue(int i) {return paramDesc[i]->getValue();}
     
        void print() {
            std::cout << "Listing Params for rule:" << ruleDesc->getName() << std::endl;
            for(std::map <int, ParameterDescription*>::const_iterator i = paramDesc.begin(); i != paramDesc.end(); i++){
                i->second->print();
            }
            std::cout << "----" << std::endl;
        }
        virtual int getScope(int i) = 0;
        virtual Rule* getRule(int i)  = 0;
     
    protected:
        RuleDescription* ruleDesc;
        std::map <int, ParameterDescription*> paramDesc;
     
    };
     
    class RuleBackToBench: public Rule{
    public:
        RuleBackToBench( RuleDescription* ruleDesc): Rule( ruleDesc) {}
     
        static RuleBackToBench* getRule(int i) {
            std::stringstream strname;
            std::stringstream strdate;
            // Recherche Scope et recuperation bon RuleDescription
            RuleBackToBench* ruleB = new RuleBackToBench(RuleDescription::getRule(getScope(i)));
            for (int i = 0; i < 5; i++){
                ParameterDescription* tmp = NULL;
                strname.str("");
                strdate.str("");
                strname << "NameParam" << i;
                strdate << "Value" << i;
                tmp = new ParameterDescription(i, strname.str(), i%2, strdate.str());
                ruleB->insertParam(i, tmp);
            }
            return ruleB;
        }
     
        static int getScope(int i) {return i;}
    };
     
    class RuleSettlement: public Rule{
    public:
        RuleSettlement( RuleDescription* ruleDesc): Rule( ruleDesc) {}
     
        static RuleSettlement* getRule(int i) {
            std::stringstream strname;
            std::stringstream strdate;
            // Recherche Scope et recuperation bon RuleDescription
            RuleSettlement* ruleB = new RuleSettlement(RuleDescription::getRule(getScope(i)));
            for (int i = 0; i < 5; i++){
                ParameterDescription* tmp = NULL;
                strname.str("");
                strdate.str("");
                strname << "NameParam" << i;
                strdate << "Value" << i;
                tmp = new ParameterDescription(i, strname.str(), i%2, strdate.str());
                ruleB->insertParam(i, tmp);
            }
            return ruleB;
        }
     
        static int getScope(int i) {return i;}
    };
     
    int _tmain(int argc, _TCHAR* argv[])
    {    
        std::stringstream strname;
        std::stringstream strdate;
        std::stringstream strdoc;
        for (int i = 0; i < 5; i++) {
            RuleTypeDescription* tmp = NULL;
            strname.str("");
            strdate.str("");
            strdoc.str("");
            strname << "Name" << i;
            strdate << "Today" << i;
            strdoc << "Doc" << i;
            tmp = new RuleTypeDescription(i, strname.str(),i, strdate.str(), strdoc.str());
            RuleTypeDescription::insertDesc(i, tmp);
        }
        RuleTypeDescription::listRules();
     
        for (int i = 0; i < 10; i++) {
            RuleDescription* tmp = NULL; 
            strname.str("");
            strdate.str("");
            strdoc.str("");
            strname << "NameRule" << i;
            strdate << "Scope" << i;
            tmp = new RuleDescription(i, strname.str(), strdate.str(), RuleTypeDescription::getRuleType(i%3));
            RuleDescription::insertDesc(i, tmp);
        }
        RuleDescription::listRules();
     
        RuleBackToBench* ruleB = RuleBackToBench::getRule(0);
        ruleB->print();
        delete ruleB;
        ruleB = RuleBackToBench::getRule(1);
        ruleB->print();
        delete ruleB;
     
        RuleSettlement* ruleS = RuleSettlement::getRule(2);
        ruleS->print();
        delete ruleS;
     
        RuleTypeDescription::kill();
        RuleDescription::kill();
     
        int i;
        std::cin >> i;
        return 0;
    }
    message d'erreur:
    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
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(159) : warning C4526: 'RuleBackToBench::getRule' : static member function cannot override virtual function 'Rule *Rule::getRule(int)'
    1>        override ignored, virtual function will be hidden
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(147) : see declaration of 'Rule::getRule'
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(176) : warning C4526: 'RuleBackToBench::getScope' : static member function cannot override virtual function 'int Rule::getScope(int)'
    1>        override ignored, virtual function will be hidden
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(146) : see declaration of 'Rule::getScope'
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(163) : error C2259: 'RuleBackToBench' : cannot instantiate abstract class
    1>        due to following members:
    1>        'int Rule::getScope(int)' : is abstract
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(146) : see declaration of 'Rule::getScope'
    1>        'Rule *Rule::getRule(int)' : is abstract
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(147) : see declaration of 'Rule::getRule'
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(183) : warning C4526: 'RuleSettlement::getRule' : static member function cannot override virtual function 'Rule *Rule::getRule(int)'
    1>        override ignored, virtual function will be hidden
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(147) : see declaration of 'Rule::getRule'
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(200) : warning C4526: 'RuleSettlement::getScope' : static member function cannot override virtual function 'int Rule::getScope(int)'
    1>        override ignored, virtual function will be hidden
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(146) : see declaration of 'Rule::getScope'
    1>c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(187) : error C2259: 'RuleSettlement' : cannot instantiate abstract class
    1>        due to following members:
    1>        'int Rule::getScope(int)' : is abstract
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(146) : see declaration of 'Rule::getScope'
    1>        'Rule *Rule::getRule(int)' : is abstract
    1>        c:\__gs\__testcpp\ruletest2\ruletest2\ruletest2.cpp(147) : see declaration of 'Rule::getRule'
    A priori tout est dit dans l erreur.
    Mais j'aurais voulu savoir si il n'etait pas possible de definir une fonction virtuel static abstraite A priori non, mais bon, je demande au cas ou...

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

Discussions similaires

  1. [03] Regles de conception-default, legende,regles de validation
    Par xavsuderrone dans le forum Modélisation
    Réponses: 4
    Dernier message: 01/02/2009, 00h14
  2. [Concept] Métadatas ?
    Par melinda dans le forum Décisions SGBD
    Réponses: 5
    Dernier message: 10/11/2004, 11h56
  3. [Concept] Réplication
    Par melinda dans le forum Décisions SGBD
    Réponses: 4
    Dernier message: 31/03/2003, 17h29
  4. [Concept] Curseur coté client et curseur coté serveur
    Par freud dans le forum Décisions SGBD
    Réponses: 2
    Dernier message: 13/09/2002, 22h13
  5. [Concept] Stabilité d'une base de donnée
    Par lassmust dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 03/07/2002, 16h16

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