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 :

API externe et Demeter


Sujet :

C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut API externe et Demeter
    Bonjour,

    une petite question existentielle concernant la loi de Demeter.
    Imaginons que, dans notre programme, nous utilisons un objet défini et implémenté dans une bibliothèque tierce. Disons que cet objet sert à envoyer du texte à un client, nous l’appellerons Sender. Concrètement, nous ne nous préoccupons pas de savoir comme s'y prend Sender; la seule chose qui nous importe c'est que lorsqu'on appelle Sender::send( my_string ) my_string soit bien envoyée au client. Mais tout de même, Sender propose tout un tas de fonctionnalités de "tuning", comme le réglage des time_out, des fonctionnalité concernant le cryptage, etc, et au final, le protocole (ensemble de fonctions membre publiques) de Sender est assez fourni.

    Afin de faciliter l'utilisation de Sender au sein de notre programme, nous décidons de l'encapsuler dans une classe à nous:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MySender
    {
    public:
      // une fonction qui permet d'envoyer un tableau de string (ce que ne permet pas Sender)
      Send( const std::vector< std::string > & my_strings );
    // ainsi que d'autres fonctionnalités qui ajoutent des traitements avant d'envoyer les chaines de caratères
     
    private:
      Sender the_sender;
    };
    Mais, en plus de ces fonctionnalités, nous voudrions pouvoir utiliser directement toutes les fonctionalités de Sender. La première solution serait de faire en sorte que MySender wrappe le protocole de Sender: pour toutes les fonctions membres publiques de Sender, on implémente la même dans MySender et on appelle the_sender.the_fonction( the_parameters );

    Seulement le protocole de Sender est long, et on a la flemme de tout réécrire. De plus, cela parait un travail inutile puisqu'il suffirait que MySender puisse renvoyer une référence constante sur the_sender et on utiliserait directement le protocole de Sender. Sauf que, cela va à l'encontre de la loi de Demeter.

    Existe-t-il un autre solution que de redéfinir tout le protocole de Sender?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Salut

    Citation Envoyé par r0d Voir le message
    Afin de faciliter l'utilisation de Sender au sein de notre programme
    (...)
    nous voudrions pouvoir utiliser directement toutes les fonctionalités de Sender
    C'est pas un peu contradictoire ces 2 besoins ? Si ta classe contient au moins les mêmes fonctionnalités, alors elle n'est pas plus simple.

    Si l'objectif est de simplifier l'utilisation, alors ta classe est un "handler" (je sais pas s'il y a un terme spécifique), c'est à dire une classe conçu pour manipuler un autre. Elle doit alors proposer une interface simple, destiné à répondre uniquement au besoin. S'il y a plusieurs besoins, il faut plusieurs handler (respect du SRP).
    Un exemple d'une telle classe, c'est stringstream, pour manipuler une string comme un flux, ou les QDataStream et QTextStream, pour manipuler QIODevice et QByteArray comme des flux.
    Dans ce cas, la classe manipulée n'est pas un détail interne, mais bien une classe externe, accessible aussi au code appelant. Il n'y a pas de violation de Déméter.


    Si tu as besoin d'exposer l'interface complète de Sender sans pour autant utiliser directement Sender, ni hériter publiquement de Sender (par exemple, pour contrôler les entrées et sorties de Sender), dans ce cas, c'est effectivement un wrapper et tu n'as pas d'autre choix que réimplémenter toutes les fonctions une par une (comme simple accesseur ou en ajoutant des contrôles dans les fonctions). Voir par exemple QOpenGLFunctions qui est un wrapper entre OpenGL (lib C) et Qt (lib C++). Dans ce cas, la classe Sender devient un détail interne, mais n'est pas exposée (retourner un getter permettrait d'appeller Sender sans passer par les fonctions dédiées et les contrôles), donc pas de violation de Déméter non plus

    Guillaume

  3. #3
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par gbdivers Voir le message
    C'est pas un peu contradictoire ces 2 besoins ?
    Effectivement, maintenant que tu le dis...
    En fait c'est là que ma question n'est pas claire: on est entre 2 chaises. D'un côté on veut wrapper l'API, et d'un autre on veut juste l'utiliser.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    2 besoins = 2 classes

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Une autre possibilité, c'est d'utiliser des fonctions libres.

    Souvent, l'interface "nouvelle" de ce type de wrapper est résumé à quelques fonctions, et aucune variable membre autre que le wrapper.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Une petite remarque.

    Soit on pense qu'on à besoin de construire une façade (parce que c'est une façade que tu propose, en encapsulant Sender), et dans ce cas la logique veut que rien de l'interface encapsulée ne soit visible par l'appelant (tu te sers de ta façade, point final). Du coup, tu est obligé de re-créer une interface de configuration de l'objet Sender sur ta façade (des objets conn_param, conn_optim, ... ?)

    Soit tu penses que c'est une bonne chose d'utiliser l'objet Sender en direct, et dans ce cas, tu n'as pas besoin de façade. Tu peux juste écrire une fonction ou deux pour encapsuler certains traitements particuliers qui son communs dans l'utilisation que tu fait de l'interface de Sender.

    Quoi qu'il en soit, les deux approches ne sont pas vraiment compatible
    [FAQ des forums][FAQ Développement 2D, 3D et Jeux][Si vous ne savez pas ou vous en êtes...]
    Essayez d'écrire clairement (c'est à dire avec des mots français complets). SMS est votre ennemi.
    Evitez les arguments inutiles - DirectMachin vs. OpenTruc ou G++ vs. Café. C'est dépassé tout ça.
    Et si vous êtes sages, vous aurez peut être vous aussi la chance de passer à la télé. Ou pas.

    Ce site contient un forum d'entraide gratuit. Il ne s'use que si l'on ne s'en sert pas.

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Une petite remarque.

    Soit on pense qu'on à besoin de construire une façade (parce que c'est une façade que tu propose, en encapsulant Sender), et dans ce cas la logique veut que rien de l'interface encapsulée ne soit visible par l'appelant (tu te sers de ta façade, point final). Du coup, tu est obligé de re-créer une interface de configuration de l'objet Sender sur ta façade (des objets conn_param, conn_optim, ... ?)

    Soit tu penses que c'est une bonne chose d'utiliser l'objet Sender en direct, et dans ce cas, tu n'as pas besoin de façade. Tu peux juste écrire une fonction ou deux pour encapsuler certains traitements particuliers qui son communs dans l'utilisation que tu fait de l'interface de Sender.

    Quoi qu'il en soit, les deux approches ne sont pas vraiment compatible
    Citation Envoyé par r0d Voir le message
    Effectivement, maintenant que tu le dis...
    En fait c'est là que ma question n'est pas claire: on est entre 2 chaises. D'un côté on veut wrapper l'API, et d'un autre on veut juste l'utiliser.
    Ceci dit, le wrapper ne fera aussi qu'uitliser l'API en question

    Mais, l'un dans l'autre, j'aurais tendance à dire que tout t'incite effectivement à fournir un wrapper pour tout ce qui touche à cette API et donc à créer, effectivement, une façade pour celle-ci.

    Il faut en effet garder en tête le point I de SOLID, qui te conseille de faire une ségrégation nette de ton interface.

    Imaginons donc que vous décidiez, dans trois mois ou dans six mois, de passer à une autre API pour le sender.

    Le fait d'avoir, dés le début, fourni une façade complète à utiliser te permettra une transition beaucoup plus facile dans le sens où le code utilisant ta bibliothèque ne devra absolument pas bouger: ton sender n'est qu'un détail d'implémentation de ta façade et l'utilisateur n'a strictement pas à savoir "ce qu'il y a derrière".

    Si, par contre, tu décides, pour une raison ou une autre, de donner directement accès à ton sender, tu peux estimer que c'est foutu: le moindre changement opérationnel concernant le choix de ce sender aura des répercussions impossibles à évaluer sur le code existant, simplement parce qu'il impliquera des changements (que l'on peut estimer être importants) au niveau du code utilisateur.

    Alors, bien sur, tu me diras que le choix de ce sender a été murement réfléchi et évalué, que vous ne comptez pas en changer de sitôt, que c'est "prévu pour durer" et qu'il n'y a aucune raison de changer d'API dans l'immédiat

    Mais tu sais aussi bien que moi qu'en informatique on ne peut être sur que d'une chose, c'est qu'on n'est jamais sur de rien, que les besoins exprimés évoluent sans cesse et nécessitent donc des adaptations constantes.

    Dés lors, je crois que la conclusion s'impose d'elle-même, non
    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

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

Discussions similaires

  1. Talend et API Externe
    Par chris81 dans le forum Développement de jobs
    Réponses: 0
    Dernier message: 21/02/2013, 18h56
  2. Licence GPL Mysql et code source, dans une API externe
    Par guillaume-13015 dans le forum Administration
    Réponses: 4
    Dernier message: 28/11/2012, 19h14
  3. Réponses: 0
    Dernier message: 13/01/2012, 16h44
  4. API externe, comment authentifier ?
    Par Phach dans le forum Langage
    Réponses: 4
    Dernier message: 06/01/2010, 10h40
  5. swf avec api externe dans un swf qui ce lance pas
    Par marcuscircus dans le forum ActionScript 3
    Réponses: 1
    Dernier message: 02/01/2010, 14h06

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