La liste des paramètres d'une méthode doit-elle contenir des objets ou des identificateurs d'objet?

10

Nos équipes ont la discussion suivante:

Disons que nous avons les deux méthodes suivantes:

public Response Withdraw(int clubId, int terminalId,int cardId, string invoice, decimal amount);

public Response Withdraw(Club club, Terminal terminal,Card card, string invoice, decimal amount);

ce qui est envoyé par câble n'est que les identifiants.

un côté dit que la première méthode est correcte, car nous n'avons que les identifiants de terminal et de club, et il doit être clair que nous n'avons rien d'autre, c'est mon approche.

l'autre côté dit que la deuxième méthode est correcte car elle est plus flexible.

Nous connaissons l'idée du paramètre d'objet, l'autre côté pense également que le paramètre d'objet devrait avoir les objets comme propriétés.

Quelle est la bonne approche?

Peut-être existe-t-il une troisième approche encore meilleure?

Mithir
la source
Quoi? ...........
James
1
Le contexte? Service Web? WCF?
CodesInChaos
1
@James - désolé d'avoir écrit cette question assez rapidement, pouvez-vous me dire ce qui n'est pas compris pour que je puisse le modifier?
Mithir
@CodesInChaos les méthodes sont en fait des méthodes BL
Mithir

Réponses:

10

La réponse dépend du contexte.

Si le client devrait avoir tous ces objets déjà disponibles , j'utiliserais les paramètres d'objet. Sinon, leur code sera plus compliqué qu'il ne devrait l'être. (Par exemple, ils auront des appels comme club.getId(), par exemple.)

Si le client ne dispose que des identifiants facilement, alors la deuxième approche est peut-être meilleure, car vous ne voudrez peut-être pas que le client assemble / charge tous ces objets si vous n'avez vraiment besoin que des identifiants.

Une option consiste à fournir les deux méthodes , afin que le client puisse choisir celle à utiliser (étant donné que cela n'encombre pas votre API)

En général, les paramètres d'objet sont plus extensibles, car si à l'avenir vous avez besoin d'un autre élément de données pour faire le travail, vous n'avez pas besoin d'introduire une autre méthode qui prend ces informations supplémentaires.

Enfin, les signatures de votre méthode ne doivent pas être dictées par les détails de ce que fait la méthode (dans votre cas, ce qui se passe exactement sur le fil). L'API devrait avoir un sens abstrait, donc si l'implémentation change, vous n'êtes pas foutu.

c_maker
la source
3
+1 J'ajouterais seulement un point: pour les méthodes appelées à distance ("over the wire"?), Le passage d'objets peut entraîner une sérialisation en profondeur d'une arborescence d'objets étendue. Les identifiants sont d'excellents substituts aux objets lorsque vous êtes préoccupé par la taille d'une charge utile d'appel distant.
Ross Patterson
1
Dans ce cas, il semble que vous soyez couplé à un ensemble d'abstractions, donc la transmission des identifiants ne vous procurera pas plus de flexibilité et augmentera probablement la probabilité que vous inversiez les paramètres. La question est de savoir dans quelle mesure le code de la méthode est couplé avec les abstractions que je transmets? Par exemple, une méthode comme "validateCreditCard (string card, string cvi)" devrait probablement rester avec des primitives pour éviter d'être étroitement couplée avec une sorte d'objet CreditCard.
ipaul
Je me rencontrerais au milieu et utiliserais une interface dans la liste des paramètres. Votre club peut alors être un club, mais aussi un sauna à l'avenir.
Pieter B
13

La première approche indique une obsession primitive . Parce que vous passez des entiers et des chaînes, il est très facile pour le programmeur de faire une erreur (par exemple en passant un clubId au paramètre terminalId). Cela entraînera des bogues difficiles à trouver.

Dans le deuxième exemple, il est impossible de dépasser un club lorsqu'un terminal est attendu - cela vous donnerait une erreur de temps de compilation.

Même ainsi, je regarderais toujours string invoice. Une facture est-elle vraiment une chaîne? Que veut amountdire? Il s'agit plus probablement d'une valeur monétaire.

Vous avez mentionné dans votre question "ce qui est envoyé par câble n'est que les identifiants". C'est correct, mais ne laissez pas cette exigence brouiller votre domaine.

La meilleure explication que j'ai vue en faveur de cette approche était dans la règle 3 de la callisthénie objet :

Un int à lui seul n'est qu'un scalaire, il n'a donc aucune signification. Lorsqu'une méthode prend un int comme paramètre, le nom de la méthode doit faire tout le travail pour exprimer l'intention. Si la même méthode prend une heure comme paramètre, il est beaucoup plus facile de voir ce qui se passe. De petits objets comme celui-ci peuvent rendre les programmes plus faciles à gérer, car il n'est pas possible de passer une année à une méthode qui prend un paramètre heure. Avec une variable primitive, le compilateur ne peut pas vous aider à écrire des programmes sémantiquement corrects. Avec un objet, même petit, vous donnez au compilateur et au programmeur des informations supplémentaires sur la valeur et pourquoi elle est utilisée.

MattDavey
la source
La deuxième approche est donc préférable? même s'il y a un objet club avec juste la propriété id remplie?
Mithir
Cela semble être un blog aléatoire. Il n'y a aucune preuve pour dire ce qui est préféré. Qui se soucie vraiment de ce qui est préféré? Faites ce qui fonctionne pour vous
James
@James Il n'y a pas de réponse définitive à cette question, d'autant plus que le PO ne nous a pas donné beaucoup de contexte. Quiconque prétend catégoriquement qu'une approche est préférable à l'autre ne rend pas service au PO. Ce n'est pas si noir et blanc.
MattDavey
1
@James J'ai simplement souligné que la première approche rend très facile l'introduction de bogues difficiles à trouver. Je ne dis pas que les types primitifs sont mauvais, mais le but des types primitifs est de créer des types de domaine significatifs. Les utiliser en dehors de ce contexte est la définition même de l'odeur du code obsessionnel primitif.
MattDavey
5
@James: Ce que MattDavey a dit est un fait bien établi. Il ne dit pas que les types natifs sont mauvais, il dit que ceci: someMethod (int, int, int, string, decimal) est beaucoup plus difficile à comprendre et à utiliser par un client que someMethod (Club, Terminal, Card, String , décimal)
c_maker
2

Il n'y a pas de bonne réponse à celle-ci. L'une ou l'autre option pourrait convenir à l'emploi. Eh bien presque de toute façon, l'argument de la facture a soulevé un sillon sur mon front, je n'ai aucune idée de ce que c'est en lisant le code.

Si vous envoyez un identifiant, les deux systèmes doivent être étroitement couplés à ce que cela représente. ClubID est la clé du tableau des clubs. Plus précisément, l'appelant et l'appelé doivent s'entendre sur le nom de la table Clubs et sur la base de données dans laquelle elle se trouve. Si vous ne voulez pas ou ne pouvez pas imposer cette contrainte, vous passeriez l'objet en utilisant une description commune, natif, sérialisé, xml, nom = valeur quelconque, un fichier ini :)

Cela, comme vous l'avez identifié, vous coûtera "sur le fil". Éviter cela en envoyant simplement l'identifiant vous coûte ailleurs. Alors, lequel vous fait le moins mal, maintenant (ou peut-être plus tard ...) est l'indicateur du bon contre le mauvais.

Tony Hopkinson
la source