web-dev-qa-db-fra.com

Est-il suffisant que les méthodes soient distinguées uniquement par leur nom d'argument (et non par type)?

Est-il suffisant de distinguer les méthodes uniquement par leur nom d'argument (et non par type) ou est-il préférable de les nommer de manière plus explicite?

Par exemple T Find<T>(int id) vs T FindById<T>(int id).

Y a-t-il une bonne raison de le nommer de manière plus explicite (c'est-à-dire en ajoutant ById) vs garder juste le nom de l'argument?

L'une des raisons pour lesquelles je peux penser est que les signatures des méthodes sont les mêmes mais qu'elles ont une signification différente.

FindByFirstName(string name) et FindByLastName(string name)

36
Konrad

Bien sûr, il y a une bonne raison de le nommer plus explicitement.

Ce n'est pas principalement la méthode définition qui devrait être explicite, mais la méthode tilisation. Et tandis que findById(string id) et find(string id) sont tous deux explicites, il y a une énorme différence entre findById("BOB") et find("BOB"). Dans le premier cas, vous savez que le littéral aléatoire est, en fait, un Id. Dans ce dernier cas, vous n'êtes pas sûr - il pourrait s'agir en fait d'un prénom ou de quelque chose d'autre.

68
Kilian Foth

Avantages de FindById () .

  1. A l'épreuve du temps : Si vous commencez par Find(int), et que vous devez ensuite ajouter d'autres méthodes (FindByName(string), FindByLegacyId(int), FindByCustomerId(int), FindByOrderId(int), etc.), les gens comme moi ont tendance à passer beaucoup de temps à chercher FindById(int). Pas vraiment un problème si vous pouvez et allez changer Find(int) en FindById(int) une fois que cela sera nécessaire - l'épreuvage futur concerne ces si s.

  2. Plus facile à lire . Find est parfaitement bien si l'appel ressemble à record = Find(customerId); Pourtant FindById est légèrement plus facile à lire si c'est record = FindById(AFunction());.

  3. Cohérence . Vous pouvez appliquer systématiquement le modèle FindByX(int)/FindByY(int) partout, mais Find(int X)/Find(int Y) n'est pas possible car ils sont en conflit.

Avantages de Find ()

  • BAISER. Find est simple et direct, et avec operator[] c'est l'un des 2 noms de fonctions les plus attendus dans ce contexte. (Certaines alternatives populaires étant get , lookup ou fetch, selon le contexte).
  • En règle générale, si vous avez un nom de fonction qui est un seul mot bien connu qui décrit avec précision ce que fait la fonction, utilisez-le. Même s'il existe un nom multi-mots plus long qui décrit légèrement mieux ce que fait la fonction. Exemple: Longueur vs NumberOfElements . Il y a un compromis, et où tracer la ligne fait l'objet d'un débat permanent.
  • Il est généralement bon d'éviter la redondance. Si nous regardons FindById(int id), nous pouvons facilement supprimer la redondance en la changeant en Find(int id), mais il y a un compromis - nous perdons une certaine clarté.

Alternativement, vous pouvez obtenir les avantages des deux en utilisant des ID fortement typés:

CustomerRecord Find(Id<Customer> id) 
// Or, depending on local coding standards
CustomerRecord Find(CustomerId id) 

Implémentation de Id<>: en tapant fortement les valeurs ID en C #

Les commentaires ici, ainsi que dans le lien ci-dessus, ont soulevé plusieurs préoccupations concernant Id<Customer> Que je voudrais aborder:

  • Préoccupation 1: C'est un abus de génériques. CustomerId et OrderID sont de types différents (customerId1 = customerId2; => bon, customerId1 = orderId1; => mauvais), mais leur implémentation est presque identique, nous pouvons donc les implémenter soit avec copier coller, soit avec métaprogrammer. Bien qu'il soit utile de discuter de l'exposition ou de la dissimulation du générique, la métaprogrammation est à quoi servent les génériques.
  • Préoccupation 2: Cela n'arrête pas les erreurs simples./C'est une solution à la recherche d'un problème Le principal problème qui est résolu en utilisant des ID fortement typés est le mauvais ordre des arguments dans un appel à DoSomething(int customerId, int orderId, int productId). Les identifiants fortement saisis empêchent également d'autres problèmes, y compris celui auquel OP a posé des questions.
  • Préoccupation 3: Cela obscurcit vraiment le code. Il est difficile de dire si un identifiant est conservé dans int aVariable. Il est facile de dire qu'un identifiant est conservé dans Id<Customer> aVariable, Et nous pouvons même dire qu'il s'agit d'un identifiant client.
  • Préoccupation 4: Ces ID ne sont pas des types forts, juste des wrappers. String est juste un wrapper autour de byte[]. L'encapsulation ou l'encapsulation n'est pas en conflit avec une frappe forte.
  • Préoccupation 5: C'est trop conçu. Voici la version minimale, bien que je recommande également d'ajouter operator== Et operator!= , si vous ne voulez pas vous fier exclusivement à Equals:

.

public struct Id<T>: {
    private readonly int _value ;
    public Id(int value) { _value = value; }
    public static explicit operator int(Id<T> id) { return id._value; }
}
36
Peter

Une autre façon de penser à ce sujet est d'utiliser le type de sécurité de la langue.

Vous pouvez implémenter une méthode telle que:

Find(FirstName name);

Où FirstName est un objet simple qui encapsule une chaîne qui contient le prénom et signifie qu'il ne peut y avoir aucune confusion quant à ce que fait la méthode, ni dans les arguments avec lesquels elle est appelée.

10
3DPrintScanner

Je voterai pour une déclaration explicite comme FindByID .... Le logiciel devrait être construit pour le changement. Il doit être ouvert et fermé (SOLIDE). Ainsi, la classe est ouverte pour ajouter une méthode de recherche similaire, comme disons FindByName .. etc.

Mais FindByID est fermé et sa mise en œuvre est testée unitaire.

Je ne proposerai pas de méthodes avec des prédicats, celles-ci sont bonnes au niveau générique. Et si, sur la base du champ (ByID), vous disposez d'une méthodologie différente.

1
BrightFuture1029

Je suis surpris que personne n'ait suggéré d'utiliser un prédicat comme celui-ci:

User Find(Predicate<User> predicate)

Avec cette approche, non seulement vous réduisez la surface de votre API, mais vous donnez également plus de contrôle à l'utilisateur qui l'utilise.

Si cela ne suffit pas, vous pouvez toujours l'étendre à vos besoins.

0
Aybe