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 :

[Architecture] Ajouter des fonctionnalités à une classe


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut [Architecture] Ajouter des fonctionnalités à une classe
    Bonjour,

    J'aurais une question d'architecture générale sur le C++.
    La question porte sur qu'elle est le meilleur moyen d'ajouter des fonctionnalités à une classe C++.
    Plus précisément, est qu'il existe un moyen de faire une "union" de classes dans le sens de faire une union de leurs méthodes ?

    Je vais illustrer ma question sur un exemple très simple.

    Imaginons que l'on est une classe "Tab" représentant un tableau creux.
    Cette classe contient des structures de données permettant de modéliser l'objet et quelques méthodes permettant de le manipuler.

    Voici une implémentation très naïve (par souci de simplicité) de la classe Tab :

    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
    class Tab {
      public:
        Tab() {
        }
     
        void set(int x, int val) {
         tab.push_back( make_tuple(x, val));
        }
     
        int get() {
         // ...
        }
     
      private:
        vector< pair<int, int> > tab;
    };

    Imaginons que l'on souhaite implémenter une fonctionnalité pour cette classe.
    Par exemple obtenir la moyenne des éléments du tableau.
    Plusieurs possibilités s'offre à nous :

    1> Modifier la classe : on ajoute dans la classe des attribues, et chaque fois qu'on l'on fait un "set", on met a jour ses attributs.
    Cette méthode à plusieurs inconvenants :
    • On alourdit la classe
    • Même si l'on n'utilise pas la fonctionnalité getMoy, des calculs seront effectués chaque fois que l'on fait un "set"



    2> Créer une fonction : on créer une fonction qui prend en argument Tab puis calcule et renvoi la moyenne.
    Cette méthode a plusieurs inconvenants :
    • Les calculs ne se font pas de manière itérative (pas forcément gênant pour cet exemple, mais on peut imaginer des cas ou ceci est un problème)
    • On n'a pas d'attribut lié à l'objet nous permettant des garder certaines informations. Pour cet exemple, on ne sauvegarde pas la valeur de la moyenne, donc chaque fois que l'on fait appelle à getMoy, on doit tout recalculer.



    3> Héritage : on créer une classe TabWithMoy qui ajoute ce dont a besoin pour calculer la moyenne.
    Inconvénients :
    • Très lourd et lent.
    • Si l'on souhaite ajouter plusieurs fonctionnalités, on doit créer une chaine d'héritage (beurk !)



    4> Héritage 2 : Utiliser le design pattern "composite"
    Inconvénients :
    • Lenteurs dues à l'héritage



    5> Algorithme en attribut : on créer une classe qui contient la structure de donné "Tab" et tous les algorithmes dont on a besoin

    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
    class TabWithSomeAlgo {
     Tab tab;
     Moy moy;
     
     void set(int x, int val) {
       tab.set(int x, int val);
       moy.set(int x, int val);
     }
     
     double getMoy() {
       return moy.getMoy();
     }
     
     int get(int x) {
       tab.get(x);
     }
    }
    Cette solution me semble être la meilleure, mais elle a encore quelques défauts.
    Chaque fois que l'on souhaite ajouter une nouvelle fonctionnalité, on doit modifier la classe "TabWithSomeAlgo" à plusieurs endroits :
    • On ajoute un attribut pour la nouvelle fonctionnalité, ET on doit faire appel à ce nouvel attribut dans toutes les méthodes qui sont également présentes dans ce nouvel attribut.




    Existe-t-il une astuce permettant de faire appel à ces méthodes de manière automatique ?
    Un truc du type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef class_union<Tab, Moy> TabWithSomeAlgo;
    De telle sorte que lorsque l'on fait appel à une méthode de TabWithSomeAlgo, cela fasse également appelle à cette même méthode pour tous les objets qui ont également cette méthode.
    Théoriquement, le compilateur a toutes les informations nécessaires pour pouvoir faire ça, mais est-ce que cela est possible à implémenter ?


    Si quelqu'un a une idée ou des remarques là-dessus ?

    Merci

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 470
    Par défaut
    La solution une ne pose aucun problème.
    Vous ajoutez 2 champs :
    - Un bool IsDirty (initialisé à true)
    - Un int ou le type retourné getMoy. On l'appelera "MoMo".

    Sur appel à la méthode set, vous mettez IsDirty à true.
    Quand vous appelez "getMoy", il vérifie si IsDirty est à false ou à true.
    S'il est à true, vous recalculez la moyenne et vous remplissez le champ "MoMo" avec cette moyenne et vous mettez IsDirty à false.
    Vous renvoyez la valeur de "MoMo".

    Voilà, solution optimale en 5 lignes maximum.

  3. #3
    Membre éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut
    Merci pour ta réponse bacelar

    C'est effectivement une solution, mais si on imagine que l'on a beaucoup de fonctionnalités à ajouter, on risque de vite se retrouver avec une très très grosse classe qui risque de devenir illisible.
    Pareille au niveau des introductions de bugs, avec l'augmentation du nombre d'attributs d'une classe (qui augmente avec le nombre de fonctionnalité que l'on implémente), on accroît les chances qu'en ajoutant ou modifiant une fonctionnalité, on se trompe et modifie des attributs destinés à une autre fonctionnalité.
    Dans l'exemple, si MoMo est visible seulement par la "fonctionnalité moyenne", cela réduirait les possibilités de bugs et aiderait à la lisibilité de la classe.

    Pareille si une fonctionnalité à implémenter est compliqué est demande des modifications de plusieurs méthodes.

    En faite, je chercherais à décomposer une classe pour chacune de ces fonctionnalités sans perdre en efficacité.
    Je ne sais pas si ce que je cherche à faire est possible en C++, mais j'ai l’impression qu'une telle architecture permettrait de rendre le code plus simple et lisible tout en facilitant l'ajout, la modification et la suppression de fonctionnalités.
    Vous en pensez quoi ? C'est une fausse bonne idée ? Ça vous semble possible en C++ ?

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Ce dont parle bacelar est d'ailleurs un simple système de cache et une mise en application classique du mot-clé mutable.

    Sinon, je dirais que tu confonds plusieurs trucs
    - soit ta classe doit fournir ceci et l'implémente
    - soit tu veux faire faire ton truc à ta classe, et dans ce cas il n'y a aucune espèce de raison de modifier la classe et il suffit de créer une fonction externe, possiblement template, pour réaliser ta manip. std::algorithm par exemple.

    Et pour C++17 (je crois), on pourra surcharger une classe avec des fonctions libres et les appeler avec la syntaxe d'appel des fonctions membres, le compilo se chargera de trouver la bonne fonction, membre ou libre, lui-même et d'y passer les paramètres

    Sinon en C# il existe la notion de partial class qui m'a toujours choqué perso.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Membre éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut
    Merci pour ta réponse Bousk

    Citation Envoyé par Bousk Voir le message
    Sinon, je dirais que tu confonds plusieurs trucs
    - soit ta classe doit fournir ceci et l'implémente
    - soit tu veux faire faire ton truc à ta classe, et dans ce cas il n'y a aucune espèce de raison de modifier la classe et il suffit de créer une fonction externe, possiblement template, pour réaliser ta manip. std::algorithm par exemple.
    C'est un peu ça oui, je veux mélanger un peu les deux pour avoir que les avantages sans les inconvenants :p

    soit ta classe doit fournir ceci et l'implémente
    Je garde évidemment ce principe.
    Une classe qui représente la structure de donnée (a la responsabilité de représenter la structure).
    Une classe pour chaque fonctionnalité (uniquement la responsabilité de fournir l'unique fonctionnalité).
    Une dernière classe agrège toutes ces classes (responsabilité unique d'agréger la structure de donnée avec les fonctionnalités que l'on souhaite posséder).

    il suffit de créer une fonction externe, possiblement template, pour réaliser ta manip. std::algorithm par exemple
    Le problème de l'utilisation de fonction externe est qu'on ne peut pas ajouter des attributs à l'objet sur lequel on fait la manipulation (j'ai pris l'exemple de mise en cache dans mon exemple simple, mais ça peut être des données plus complexes).
    L'idée est que lorsque l'on souhaite ajouter une nouvelle fonctionnalité sur un objet, il est parfois nécessaire de lui rajouter des données.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Si tu ajoutes des membres, tu altères l'objet; Si tu altères l'objet, c'est un objet différent. L'architecture c'est une vraie chose, c'est pas juste "tiens je vais ajouter un membre 'moyenne' à mon vector pour calculer la moyenne", non.
    Un objet doit avoir un but, une collection sert juste à stocker des objets et ne devrait pas avoir de notion de calcul et mise en cache de quoi que ce soit, sinon ce n'est déjà plus une simple collection.

    Si tu veux juste faire n'importe quoi avec des objets, il existe Python.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

Discussions similaires

  1. [Débutant] Ajouter des attributs à une classe générée automatiquement par Entity
    Par Pelote2012 dans le forum Entity Framework
    Réponses: 2
    Dernier message: 20/11/2014, 16h07
  2. Réponses: 8
    Dernier message: 21/01/2014, 11h52
  3. Ajouter des méthodes à une classe annotée
    Par ThomasEscolan dans le forum Langage
    Réponses: 2
    Dernier message: 04/09/2012, 17h29
  4. comment ajouter des méthodes à une classe lors Runtime?
    Par revever dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 31/03/2008, 13h53

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