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 :

Séparation Calcul et Représentation


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 89
    Points : 50
    Points
    50
    Par défaut Séparation Calcul et Représentation
    Bonjour,

    Je cogite sur la question suivante - j'ai une courbe paramétré C(t) que je représente par une classe (disons C) qui contient notamment une méthode pour calculer un point de la courbe (exemple - courbe de Bézier, algorithme de Casteljau). Pour dessiner la courbe, je peux rajouter une méthode qui va calculer le point et le tracer dans la foulée. Mais je ne pense pas que ce soit la bonne méthode de mélanger calcul et représentation, et je m'interroge sur la "best practice" pour séparer les deux. J'ai pensé aux possibilités suivantes (en supposant que je calcule les points et les stockes dans un <vecteur> qui est un param de la classe)
    - ajouter à la classe une fonction amie qui permet d'accéder au vecteur des points pour dessiner le point
    - laisser le vecteur "private" mais ajouter un itérateur public. Créer ensuite une fonction (qui n'est pas amie) qui prend en paramètre cet itérateur et dessine les points (variante: prend comme paramètre la classe C, ce qui permetrait de différencier la fonction dessiner "courbe" de dessiner "point"
    - dans un contexte d'extensibilité de la solution, on peut penser qu'il y ait différentes versions de la fonction dessiner (par exemple en fonction des plateformes/OS). Du coup, pourquoi ne pas inclure une Factory (classe Context), inclure dans la classe C la classe Context (composition) qui a une méthode virtuelle "dessiner". En fonction des plateformes, il y a une fonction "dessiner" différente.

    J'imagine que ce genre de problème est un "classique" et je voudrais savoir si il y a une "best practice".
    En vous remerciant par avance.
    Christian

  2. #2
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Hello !

    Citation Envoyé par coberle Voir le message
    Pour dessiner la courbe, je peux rajouter une méthode qui va calculer le point et le tracer dans la foulée. Mais je ne pense pas que ce soit la bonne méthode de mélanger calcul et représentation
    Et tu as raison. Dans l'ensemble à te lire, je trouve que tu te poses les bonnes questions. Fort heureusement, il est assez facile d'y répondre avec un peu de méthode. L'idée générale est de penser en terme de responsabilités. Chaque classe (ou instance de classe) a un rôle à remplir, et ne doit pas en remplir plusieurs en même temps. Ici, il y a plusieurs rôles à distribuer:

    • Représenter la courbe au sens mathématique.
    • Calculer des points de cette courbe et exposer publiquement cette liste.
    • Afficher ces points à l'utilisateur.


    Même si le calcul est peu coûteux et que tu peux te permettre de le refaire à chaque rafraîchissement de l'affichage, il te faudra une abstraction entre le calcul des points et la méthode de dessin. Le premier rôle sera rempli par ta classe existante C. Elle doit posséder une fonction qui prend une valeur du paramètre t et retourne le point associé à cette valeur. Une seconde classe va appeler cette fonction et stocker le résultat dans une collection (par exemple un vecteur). Une dernière classe s'occupera de l'affichage. C'est dans cette dernière classe que tu ajouteras de la virtualité si tu souhaites obtenir un comportement polymorphe. Le polymorphisme de la méthode de dessin ne doit en aucun cas affecter la classe C, car leur rôles n'ont aucun lien.


    Pour le coup, nul besoin d'utiliser l'amitié, tu peux architecturer quelque chose avec une interface dans ce goût 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
    23
    24
    25
    26
    27
    class Point {};
     
    class Courbe {
     public:
      Point CalculerPoint(double t);
    };
     
    class NuageDePoints {
     public:
      NuageDePoints(Courbe const& courbe, double t_debut, double t_fin, double t_pas);
      std::vector<Point> const& ListeDesPoints() const;
    };
     
    class Afficheur {
     public:
       virtual void Dessiner(NuageDePoints const& nuage) = 0;
    };
     
    class AfficheurEcran : public Afficheur {
     public:
       virtual void Dessiner(NuageDePoints const& nuage) override;
    };
     
    class AfficheurPDF : public Afficheur {
     public:
       virtual void Dessiner(NuageDePoints const& nuage) override;
    };
    Find me on github

  3. #3
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    La solution de @jblecanard est bonne.

    J'en profite pour poser une question : si le nuage de points n'est destiné qu'à être "affiché" (afficher peut vouloir dire stocker ça dans un fichier, comme un PDF dans l'exemple), alors j'aurais fusionné NuageDePoints et Afficheur personnellement.

    Le rôle de NuageDePoints n'a de sens que si on peut faire plusieurs actions différentes dessus au final.

    Est-ce que cette fusion est correcte ?
    Il y à deux rôles, mais ils sont liés, d'où mon interrogation sur la création d'une classe supplémentaire.

    En reprenant l'exemple, je verrais quelque chose comme ça
    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
    struct Point { double x, y; };
     
    class Courbe {
    public:
    	Point /* double ? */ operator()(double x) const;
    };
     
    class Afficheur {
    	std::reference<Courbe const> m_courbe;
    	std::vector<Point> m_points;
    	double m_min;
    	double m_max;
    	double m_pas;
     
    protected:
    	std::vector<Point> const& points() const { return m_points; }
     
    public:
    	double min() const { return m_min; }
    	double max() const { return m_max; }
    	double pas() const { return m_pas; }
    	void update(double min_, double max_, double pas_); // set le min/max/pas et recalcule les points
    	virtual void Dessiner() const = 0;
    };
     
    class AfficheurEcran : public Afficheur {
    public:
    	virtual void Dessiner() const override;
    };
     
    class AfficheurPDF : public Afficheur {
    public:
    	virtual void Dessiner() const override;
    };

  4. #4
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Quelques remarques, en plus de ce qui a déjà été dit :
    - pour moi, il n’est clairement pas du rôle de la courbe de stocker ses points. De toute façon, ça n’a pas de sens pour une courbe paramétrée.
    - et de manière encore plus générale, ça ne sert à rien de stocker la totalité des points

    Je vois donc les choses de la manière suivante :
    - ta classe Courbe, tu n’y touches pas. Tu gardes la méthode CalculerPoint
    - tu crées une classe CourbeDiscrete(double debut, double fin, double pas). Cette classe tient juste une référence vers Courbe, et fournit un CourbeDiscrete::iterator à l’aide de méthode begin)() / end(). Cet itérator renvoie, lorsqu’il est déréférencé, la valeur de point correspondant, càd begin() renvoie la valeur de Courbe.calculerPoint(debut), au premier incrément, cela renvoie la valeur de Courbe.calculerPoint(debut + pas), etc. end() n’est pas déréférençable. Cette classe doit donner accès au valeurs de début, fin et pas qu’on lui a donné à la construction, car la vue peut en avoir besoin.

    L’avantage de faire ça est que tu n’imposes pas à l’utilisateur de tout stocker en mémoire s’il n’en a pas besoin (et qui peut être gênant si tu veux les valeurs sur des millions de points, pour les écrire dans un fichier par exemple). Quant au fait de séparer Courbe / CourbeDiscrete, c’est pour moi une question de sémantique : les deux classes ont un comportement très différent, l’une est une courbe paramétrée, l’autre une liste de point avec une « résolution » donnée. On pourrait stocker tout cela dans l’itérateur, mais personnellement j’aime moins cette idée.

    - pour ce qui est de la méthode Dessiner, j’en ferais plutôt une fonction libre, qui à partir d’une source de points (une CourbeDiscrete, donc), va les écrire dans un Afficheur selon un algorithme déterminé. Par exemple, il y a différents moyens de tracer une série de points, en particulier de tracer les pixels intermédiaires. Ces méthodes sont indépendantes de l’afficheur utilisé, qui doit seulement offrir des « primitives » communes. Ainsi, tu peux combiner indifféremment différents algorithmes de dessin, différents afficheurs et différentes courbes.

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    J'en profite pour poser une question : si le nuage de points n'est destiné qu'à être "affiché" (afficher peut vouloir dire stocker ça dans un fichier, comme un PDF dans l'exemple), alors j'aurais fusionné NuageDePoints et Afficheur personnellement.

    Le rôle de NuageDePoints n'a de sens que si on peut faire plusieurs actions différentes dessus au final.
    Tout dépend des besoins effectivement, du coût en calcul de ces points, du fait qu'on partage ou pas le résultat entre plusieurs objet. Je me suis dit la même chose en rédigeant mais au final je voulais que la réponse soit la plus simple possible pour l'op et bien mettre en valeur le principe de découpage de responsabilités.
    Find me on github

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    89
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 89
    Points : 50
    Points
    50
    Par défaut
    Merci pour vos conseil et recommendations.
    Christian

Discussions similaires

  1. [XL-2007] Erreur de représentation d'une date calculée
    Par gv33858 dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 25/03/2011, 12h24
  2. Séparation affichage calculs
    Par Mazus dans le forum MXML
    Réponses: 2
    Dernier message: 23/11/2009, 19h37
  3. barre représentant la progression des calculs
    Par fontaigo dans le forum AWT/Swing
    Réponses: 5
    Dernier message: 26/04/2006, 12h37
  4. [TP7] Calculer sin, cos, tan, sqrt via le FPU
    Par zdra dans le forum Assembleur
    Réponses: 8
    Dernier message: 25/11/2002, 05h09
  5. Algo de calcul de FFT
    Par djlex03 dans le forum Traitement du signal
    Réponses: 15
    Dernier message: 02/08/2002, 18h45

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