29 votes

modèle de commande retournant le statut

Une fois, j'ai eu une discussion sur la conception, par rapport au modèle de commande. Mon collègue a déclaré qu'un objet de commande ne devrait pas renvoyer l'état (réussi, non réussi et pourquoi) après l'appel de la méthode .execute(). La raison en est que vous ne devez pas vous préoccuper de savoir si la commande est exécutée ou non, car la commande ne doit pas contenir d'état. Vous devez cependant vérifier après l'invocation si la commande a eu l'effet escompté. Un autre point qu'il a fait valoir est que sur le Gang of Four, le pattern de commande ne présente pas ce cas (de retour d'état).

J'ai soutenu le point opposé. Le GoF ne présente pas ce cas, mais un modèle peut être modélisé selon vos besoins. Si une commande échoue, le client qui l'invoque doit recevoir une preuve de l'état, et éventuellement déployer une réaction appropriée. Forcer le client à vérifier si l'action a réussi était source d'erreurs et produisait du code dupliqué. De plus, il y a des cas où la commande produit un résultat (par exemple, une commande qui ajoute une ligne à un graphique, aura d'une manière ou d'une autre l'identifiant de la ligne à renvoyer au client), et prétendre avoir des commandes sans état signifiait que vous deviez "repêcher" le nouvel identifiant d'objet dans le modèle de données.

Finalement, nous avons trouvé un compromis en ne renvoyant pas le statut mais en conservant les identifiants des objets nouvellement créés dans l'objet de commande, et l'application a quand même bien fonctionné, mais je suis maintenant curieux de connaître votre opinion également.

Modifier : J'ai décidé d'ajouter une petite prime. Mon espoir est d'enrichir la question avec des cas réels d'utilisation du pattern Command dans des environnements de production.

Edit 2 : Remettre la question avant la fin du bounty (demain)

23voto

Thomas Owens Points 45042

Je n'ai pas de Design Patterns : Elements of Reusable Object-Oriented Software sous les yeux pour le moment, mais je suis presque sûr que les auteurs disent même que les modèles de conception qu'ils présentent sont un modèle qui peut être modifié pour s'adapter à une situation spécifique.

Cette question touche au cœur de ce qu'est un modèle de conception - un modèle. Ce n'est pas quelque chose qui doit être mis en œuvre selon les règles de l'art. Vous avez identifié un cas où une modification logique du modèle tel qu'il est présenté dans le livre aurait aidé l'application, et c'est tout à fait normal, surtout si vous pesez les avantages et les coûts.

8voto

Janusz Points 52607

Il y a deux questions dans la question avec des réponses multiples :) La première question est la suivante : une commande doit-elle renvoyer un état d'erreur ?

Il n'y a pas de réponse claire pour chaque programme ; chaque fois que vous appliquez le modèle, vous devez y réfléchir à nouveau.

Une des choses auxquelles vous devez penser est :

  • Est-ce que j'ajoute un couplage supplémentaire à de nombreuses commandes et aux clients pour seulement quelques cas d'erreur spécifiques ?

Dans le pire des cas, vous avez de nombreuses commandes qui ne se soucient pas des erreurs, mais une ou deux commandes font quelque chose d'important pour que le client sache si cela a fonctionné. Vous ajoutez maintenant des exceptions vérifiées à l'interface et ainsi chaque client et chaque commande sont liés à la gestion des erreurs et sont couplés à l'exception. Si vous avez un client qui ne traite que les commandes qui ne lèvent pas d'exceptions, vous avez une surcharge importante dans votre code.

C'est une chose que vous ne voulez pas avoir. Vous pouvez donc soit déplacer les commandes qui nécessitent une gestion des erreurs hors de la structure de commande parce qu'elles semblent différentes des autres commandes, soit, si votre langage le permet, ajouter des exceptions d'exécution qui ne sont gérées que par les clients concernés et lancées par les commandes qui doivent les lancer.

L'autre extrême est que chaque commande peut échouer et que le client a une manière cohérente de traiter les erreurs, ce qui signifie que les erreurs ne dépendent pas de la commande spécifique. Le client n'a pas besoin de savoir quel type de commande a échoué, il peut traiter chaque erreur de la même manière. L'interface de la commande pourrait renvoyer un état d'erreur et le client pourrait traiter les erreurs. Mais le traitement des erreurs ne devrait pas dépendre du type de commande pour le client.

La deuxième question est la suivante : un commandement doit-il avoir un état ?

Il existe des architectures où une commande a besoin d'un état et d'autres où elle n'en a pas besoin.

Quelques possibilités pour décider cela :

  • Si vous voulez avoir une annulation pour votre commande, les commandes doivent avoir un état.

  • Si les commandes ne sont utilisées que pour cacher une fonction qui fonctionne avec un petit ensemble de paramètres et que les résultats ne dépendent que de la commande, comme le modèle d'état, il n'est pas nécessaire d'avoir un état et vous pouvez utiliser le même objet à plusieurs reprises.

  • Si vous utilisez la commande pour communiquer entre les threads et que vous voulez transférer des données d'un thread à un autre, la commande a besoin d'un état.

  • ... Si vous pensez que quelque chose devrait figurer dans cette liste, laissez un commentaire.

7voto

Zac Thompson Points 7754

Je vais me référer à "Head First Design Patterns". Les exemples qu'ils utilisent pour le Command Pattern sont les suivants :

  1. le scénario du diner (le client crée la commande, le personnel de service l'invoque en criant au personnel de cuisine, et le personnel de cuisine reçoit la commande)
  2. le scénario de la télécommande (la personne clique sur un bouton, la télécommande invoque la commande et le dispositif la reçoit)

Évidemment, dans le premier cas, une sorte d'état est produit par le récepteur : "voici la bouffe", ou "nous n'avons plus de pain de seigle". Dans un restaurant chic, cela peut se faire par le biais d'un traitement des exceptions à un niveau supérieur (le maître d'hôtel vient à la table et s'excuse, propose un substitut et compense votre dessert), et le personnel de service n'a rien d'autre à faire que d'invoquer correctement les commandes. Mais dans un restaurant, si le cuisinier décide de remplacer le pain par du pain brun, le personnel de service (et le client) doit être capable de gérer cette situation sans avoir à regarder le comptoir en se demandant "où est mon thon sur pain de seigle". Ce point n'est pas abordé directement dans le livre, mais je pense que c'est clairement un cas valable.

Mais dans le second scénario, l'invocateur est délibérément rendu stupide. Il ne va pas vous montrer une erreur si quelque chose ne va pas, il n'aura simplement aucun effet. Toute l'intelligence est dans le client pour déterminer si sa commande a réussi en temps voulu ("merde, j'ai oublié de le brancher"), ou dans le récepteur pour savoir quoi faire ("lire le CD : fermer d'abord le plateau du CD").

Je ne suis pas un expert, mais je dirais que renvoyer le statut à l'invocateur est tout à fait acceptable pour certaines applications.

4voto

AlbertoPL Points 8644

C'est discutable, mais cela montre clairement les deux styles de pensée :

  • Vérifier si quelque chose est correct, puis procéder en conséquence.
  • Procéder de toute façon et faire face à la situation si quelque chose de grave se produit.

Je ne pense pas qu'une méthode soit meilleure qu'une autre. Par exemple, en Java, il est généralement préférable de ne pas abuser de la gestion des exceptions et de s'occuper de tout problème éventuel avant de simplement jeter les mains (et les exceptions) en l'air. Avec Python, il est plus préférable d'aller de l'avant et d'essayer de faire ce que l'on veut, quel que soit le code d'état, et de laisser toute exception être traitée en conséquence.

C'est à vous de décider si vous souhaitez ou non que le modèle de commande renvoie un état.

4voto

teabot Points 7711

Le problème ne serait-il pas que la commande sera exécutée par une classe d'exécutants qui n'aura aucune connaissance directe de ce que fait réellement la commande ?

Si nous parlons d'ajouter un type de retour à la méthode d'exécution, il y a un potentiel pour exposer à l'exécuteur des types de retour spécifiques à l'implémentation. Je veux dire par là que vous ouvrez la porte à une situation où différentes commandes pourraient avoir différents ensembles de valeurs de retour. Si l'exécuteur devait les gérer, il deviendrait plus étroitement lié aux implémentations des commandes.

Cependant, j'ai souvent donné un état aux commandes - en leur permettant d'être configurées avec des valeurs de travail par le client lors de la construction, puis en fournissant des getters pour permettre au client d'extraire les résultats de l'exécution de la commande à la fin. Dans ce cas, je n'ai peut-être pas suivi strictement le modèle de commande, mais la conception a bien fonctionné et, à moins qu'il y ait une odeur de code définie à ce sujet, est-ce vraiment un problème ?

Nota: Cela dit, je serais intéressé d'entendre des réflexions sur les raisons pour lesquelles cela peut être une odeur de code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X