Qu'est-ce qu'un argument de sortie, tel que mentionné dans Martin's Clean Code?

14

À la page 45 du code propre de Robert C. Martin: un manuel de fabrication de logiciels agiles, Martin écrit que les arguments de sortie doivent être évités. J'ai du mal à comprendre la signification de "l'argument de sortie" et pourquoi il faut les éviter.

L'exemple de Martin pour un argument de sortie appendFooter(s);appelle la fonction public void appendFooter(StringBuffer report). Son amélioration du code estreport.appendFooter();

C'est peut-être dû au manque de contexte de code, mais je ne vois pas comment l'utilisation d'arguments de sortie est considérée comme un mauvais codage. Quelqu'un pourrait-il expliquer le concept ou donner un exemple supplémentaire de code pour comprendre cela?

La fonction suivante serait-elle également considérée comme un exemple de code impur selon le principe ci-dessus?

int[] numberArray = {3, 5, 7, 1};
sortArray(numberArray);

Si ce qui précède est une violation du principe de Martin de ne pas utiliser d'arguments de sortie, serait-il préférable d'avoir un objet qui a un tableau comme champ et une fonction qui peut être appelée pour trier le tableau?

ObjectWithArrayField numberArray = new ObjectWithArrayField(3, 5, 7, 1);
numberArray.sort();
WP0987
la source

Réponses:

11

Bob Martin parle simplement de lisibilité .

Le problème avec l' appendFooterexemple est que si vous trouvez la ligne de code appendFooter(s)quelque part dans un programme, il n'est pas immédiatement évident si cet appel prend sen entrée et l'ajoute quelque part, ou s'il sest simplement passé pour prendre la sortie de cette fonction. Pour être sûr, vous devez vérifier la documentation de la fonction. Un appel comme report.appendFooter(), cependant, évite ce problème: il est beaucoup plus évident maintenant ce qui se passe.

Notez cependant que Bob Martin ne dit pas "n'utilisez jamais d'arguments de sortie", il dit "en général, vous devriez l'éviter, car cela vous aidera à garder votre code un peu plus propre". Il ne s'agit donc pas d'une règle de bravoure culte qui devrait être suivie aveuglément.

Sortles méthodes pour les tableaux et les collections standard sont un peu différentes. Avoir la sortméthode une fonction membre de chaque type de données de tableau standard aurait quelques inconvénients du point de vue du concepteur de langage, par exemple, avoir une méthode comme Array.sortpermet de garder cela dans la bibliothèque standard, en dehors du runtime Java. Mais si vous souhaitez créer un type de collection individuel qui doit parfois être trié, l'ajout en sorttant que fonction membre peut en effet être une meilleure idée que de le placer dans une classe distincte.

Doc Brown
la source
2
sortArray(numberArray), bien sûr, trie numberArrayen place. Ou fait-il une copie de numberArray, trie la copie et retourne la copie triée sans la modifier numberArraydu tout?
8bittree
@ 8bittree: c'est vrai, mais ce n'est pas le point de discussion ici - une sort()méthode d'un conteneur peut également fonctionner sur place, sans utiliser un "argument de sortie". Donc, tout simplement parce qu'il sortArray(numberArray)s'agit d'une méthode sur place n'est absolument pas une raison qui justifie la "forme d'argument de sortie".
Doc Brown
1
Mon point était plus que ce n'est pas tout à fait évident ce qui sortArray(numberArray)se passe. Cela peut être évident s'il ne retourne pas le même type qu'il accepte, alors il doit être en place. Mais sans voir le type de retour, ou si le type de retour correspond au type d'entrée, ce n'est pas clair sans regarder la définition.
8bittree
1
@ 8bittree: Ok, tu m'as eu, j'ai retiré la déclaration en jeu de ma réponse. Cependant, le problème que vous décrivez ne disparaît pas en utilisant une fonction membre - même une fonction membre de "tri" pourrait se comporter de cette façon.
Doc Brown
11

Il s'agit d'utiliser un mécanisme inattendu pour renvoyer une valeur de la fonction, ce qui est généralement le résultat de trop faire dans la fonction ou d'avoir des responsabilités mal alignées. De loin, la meilleure façon de communiquer le résultat d'une fonction est d'utiliser la valeur de retour. J'espère que cela va de soi. Dans les langages orientés objet, la deuxième méthode consiste à muter l'objet.

Entre ces deux options, il y a tellement de façons claires et évidentes de communiquer le résultat d'une fonction que si vous vous retrouvez à vouloir muter les arguments comme seul moyen, quelque chose a mal tourné dans votre architecture. Vous devez réorganiser vos responsabilités de classe afin que celui qui effectue la mutation soit propriétaire des données en premier lieu.

La seule exception concerne les algorithmes très génériques. Par exemple, un algorithme de tri peut à juste titre être séparé des conteneurs qu'il trie, s'il peut être appliqué de manière générique à tout type de conteneur à l'aide de son interface publique. Une appendFooterfonction ponctuelle n'a pas cette excuse.

Karl Bielefeldt
la source