12
votes

Viblement de la valeur en tant que paramètre de retour

J'ai cette interface: xxx pré>

Cela fonctionne bien pour la plupart des utilisations. Mais lorsque j'essaie de modéliser une commande qui n'a que des effets secondaires (par exemple sans valeur de retour), je suis tenté d'écrire: p> xxx pré>

est-ce un problème courant? Y a-t-il de meilleures pratiques pour modéliser les commandes code> avec et strud> sans valeur de retour? P>

J'ai essayé avec cet adaptateur, mais je pense que ce n'est pas optimal pour plusieurs Raisons: P>

public abstract class VoidCommand implements Command<Void> {

    @Override
    public Void execute(String... args) {
       execute2(args);
       return null;
    }

    public abstract void execute2(String... args);
}


0 commentaires

8 Réponses :


3
votes

Gardez l'interface tel qu'il est: C'est pourquoi le void est dans la bibliothèque standard. Juste aussi longtemps que tout ce qui appelle la commande s'attend à ce que NULLS retienne.

et oui, NULL est la seule valeur que vous pouvez revenir pour annuler. P>

Mise à jour 2017 h2> pour Les dernières années, j'ai évité annulé code> comme types de retour, sauf si la réflexion est concernée. J'ai utilisé un modèle différent que je pense est plus explicite et strong> évite les nulls. C'est-à-dire que j'ai un type de réussite que j'appelle ok code> qui est renvoyé pour toutes les commandes telles que l'OP. Cela a très bien fonctionné pour mon équipe et a également propagé dans l'utilisation d'autres équipes. P>
public enum Ok { OK; }

public class SideEffectCommand implements Command<Ok> {
    @Override
    public Ok execute(String... args) {
        ...
        return Ok.OK; // I typically static import Ok.OK;
}


2 commentaires

Je pense que la principale raison du vide est de représenter le type de méthodes de retour du vide (réflexion). Au moins retour à JDK 1.1 quand il a été inclus.


Oui, ça prédate les génériques. En effet, il est utilisé dans les génériques n'est qu'une convention, même si elle est évidente.



2
votes

Qu'est-ce qui est intéressant dans votre exemple est l'utilisation de types paramétrés. Habituellement, vous auriez

interface Command<T> {
    public T execute(T someObject);
}


0 commentaires

1
votes

que problème n'est pas que commun, mais ni aussi rare ... je pense avoir vu une discussion à ce sujet il y a quelque temps, sur des appelables qui ne rentrent rien .

Je suis d'accord avec les autres affiches qu'il s'agit d'une bonne solution, beaucoup mieux que d'utiliser des objets ou un autre espace réservé factice.


1 commentaires

Pouvez-vous relier la discussion s'il vous plaît?



10
votes

Je tiens à utiliser Void explicitement. Il est facile de voir ce qui se passe sans autre classe impliquée. Ce serait bien si vous pouviez remplacer un Void retour avec void (et integer avec int , etc.) , mais ce n'est pas une priorité.


3 commentaires

Lire les réponses que je dois dire que c'est le seul qui engage le problème au lieu de commenter la vie en général.


+1 pour cette réponse. Ne vous laissez pas accrocher sur le système de type de Java étant un peu maladroit avec l'interaction entre des types à base d'objets et primitifs.


Cet article ne traite pas de ce qui se passe lorsque le code s'attend à une déclaration sur une commande qui renvoie NULL.



3
votes

Ce n'est pas un problème courant. Le problème que vous devez adresser est l'attente de votre interface. Vous combinez le comportement d'une interface d'effet non côté avec une interface qui permet aux effets secondaires.

considère ceci: p> xxx pré>

il n'y a rien de mal à utiliser code> comme type de modèle mais lui permettant de mélanger avec des implémentations pour "commande code>" signifie que certains clients de l'interface peuvent ne pas s'attendre à un résultat du vide. Sans modifier l'interface, vous avez autorisé une implémentation de créer un résultat inattendu. P>

Lorsque nous passons autour des ensembles de données à l'aide des classes de collecte, mon équipe a accepté de Jamais fort> Retour NULL Même s'il est bien syntaxiquement. Le problème était que les classes qui utilisaient les valeurs de retour devraient constamment vérifier pour un voilé pour empêcher une NPE. En utilisant le code ci-dessus, vous le verriez partout: p> xxx pré>

car il existe maintenant un moyen de savoir si la mise en œuvre a réellement un objet ou est null. Pour un cas particulier, assurez-vous que vous sachiez parce que vous connaissez votre mise en œuvre. Mais dès que vous commencez à les regrouper ou passez au-delà de votre horizon de codage (utilisé comme bibliothèque, maintenance future, etc.) Le problème NULL se présentera. P>

Ensuite, j'ai essayé ceci: P>

public static void reportResults(String results){


0 commentaires

4
votes

ça me va bien. Comme les autres ont dit, void était conçu à l'origine pour le mécanisme de réflexion, mais il est maintenant utilisé dans les génériques assez souvent pour décrire des situations telles que la vôtre.

Même mieux: Google, dans leur cadre GWT, utilisez la même idée dans leurs exemples pour un rappel retourné Void ( Exemple ici ). Je dis: Si Google le fait, il doit être au moins ok .. :)


0 commentaires

4
votes

Voici une implémentation de la meilleure des mondes multiples. XXX

Avec cette implémentation, les clients peuvent parler d'une commande si elles ne se soucient pas de la Valeur de retour et un valuedCommand Si le besoin d'une commande qui renvoie une certaine valeur.

sur la seule raison de ne pas utiliser Void tout droit est tout le inesthip renvoyé null; les déclarations que vous serez forcées d'insérer.


3 commentaires

Qu'en est-il de tous les "if (résultats! = Null) {}" Vous devez insérer dans les méthodes d'appel?


Si vous ne savez pas que votre commande renvoie void , vous ne devriez probablement pas tester le résultat pour null , car vous n'auriez rien à voir avec elle à part Passez-le de toute façon.


La raison pour laquelle vous testez pour NULL est d'empêcher une nullpointerexception qui se produira »si vous ne savez pas que votre commande renvoie NUL». L'ignorant en ne mettant pas dans le si (résultats! = Null) {} garantit presque une NPE à l'avenir. C'est pourquoi vous ne mélangez pas les interfaces.



-1
votes

Et si au lieu d'avoir une interface comme: xxx pré>

vous avez plutôt: p> xxx pré>

alors les appelants feraient: P >

public void doSomething(Command<?> cmd) {
    cmd.execute(args);
    if(cmd.hasResult()) {
        // ... do something with cmd.getResult() ...
    }
}


6 commentaires

Cela a le problème malheureux de compléter les implémentations de commandement et de ne pas être le fil-coffre-fort.


Et aussi, il complique des choses pour l'appelant.


C'est parfaitement le fil-sûr aussi longtemps que la commande .execute est idempotent, ce qui est généralement de savoir comment j'ai vu le modèle de conception de commandement mis en œuvre. Il applique également la séparation de la requête de commande (voir EN.Wikipedia.org/wiki/Command-Query_Separation). Mais vous avez raison, cela signifie que vous ne pouvez pas appeler la commande .Execute () à partir de threads multiples. Bien que si c'est ce dont vous aviez besoin, je ferais toujours la commande .execute () synchronisée (commande .getresult () seul devrait être threadsafe, bien que cela dépend du type de résultat que vous retournez ... )


GetResult a le problème même de mon exécuté: si t est vide, dois-je retourner null?


@DFA: Si t est annulé, lancez une exception. Les appelants ne doivent jamais appeler GetResult () sans vérifier HASRESULT () d'abord, tout code qui frappe ce cas est une erreur. Au moins, c'est comme ça que je le ferais, mais il apparaît que tout le monde dans ce fil n'est pas d'accord avec moi.


@Daniel Pryden: Je ne suis pas en désaccord avec vous. Le problème n'est pas comment pourriez-vous le coder, c'est ce que le code devrait s'attendre. Vérification du hasrsult () fonctionnerait mais il complique la relation entre la commande et ses clients en faisant explicitement les clients (ou les enfants) sur le comportement de la commande . @DFA demande aux moyens de rendre le couplage plus implicite afin que le code client sait toujours s'il faut revenir / vérifier pour NULL. Vérification toujours de la vérification du hasrsult () partout équivaut à avoir le code suivant d'Everwacther: si (réponse! = Null) {}