Loi de Déméter stipule ce qui suit:
C # 6.0 a introduit un nouvel opérateur appelé opérateur à condition nulle . À mon humble avis, il facilite le codage et améliore la lisibilité. Mais cela facilite également l'écriture de code plus couplé, car il est plus facile de parcourir les champs de classe, en vérifiant déjà la nullité (quelque chose comme var x = A?.B?.C?.D?.E?.F?
).
Est-il exact de dire que ce nouvel opérateur va à l'encontre de la loi de Déméter?
Est-il exact de dire que ce nouvel opérateur va à l'encontre de la loi de Déméter?
* L'opérateur conditionnel nul est un outil du langage et du framework .NET. Tout outil peut être utilisé abusivement et utilisé de manière à nuire à la maintenabilité d'une application donnée.
Mais le fait qu'un outil puisse être abusé ne signifie pas nécessairement qu'il a d'être abusé, ni que l'outil viole un ou des principes particuliers pouvant être retenus.
La loi de Déméter et d'autres sont des lignes directrices sur comment vous devez écrire votre code. Il est destiné aux humains, pas aux outils. Ainsi, le fait que le langage C # 6.0 dispose d'un nouvel outil n'affecte pas nécessairement comment vous devez écrire et structurer votre code.
Avec tout nouvel outil, vous devez l'évaluer comme ... si le gars qui finit par maintenir votre code sera un psychopathe violent ... . Notez à nouveau qu'il s'agit d'un guide pour la personne qui écrit le code et non des outils utilisés.
Sorte de.
Si vous ne faites qu'un seul accès (a?.Foo
) alors c'est équivalent à:
a == null ? null : a.Foo
que la plupart des gens seraient d'accord n'est pas une violation de la loi de Déméter. À ce stade, il ne s'agit que de sucre syntaxique pour améliorer la lisibilité.
Rien de plus que cela, et cela violerait probablement la loi de Demeter, et cette fonctionnalité a tendance à promouvoir ce type d'utilisation. Je dirais même que le "bon" usage ci-dessus ne suffit pas à lui seul à justifier ce type de changement de langage, donc je m'attends à ce qu'il soit fait pour supporter le moins clairement bon usage.
Cela dit, il convient de rappeler que la loi de Déméter n'est pas une loi en soi, mais plutôt une ligne directrice. Beaucoup de code le viole et fonctionne bien. Parfois, la simplicité de la conception ou du code vaut plus que le risque posé par la violation de la loi de Déméter.
Considérons à la fois l'opérateur seul et l'utilisation fortement enchaînée que vous en avez.
Seul .?A
dépend de la même connaissance de la classe que la valeur de gauche est et du type retourné par la méthode comme .A != null
le fait, à savoir. Il doit savoir que la propriété A
existe et renvoie une valeur qui peut être comparée à null
.
Nous ne pouvons affirmer que cela viole la loi de Demeter que si les propriétés typées le font. Nous ne sommes même pas obligés d'avoir A
comme type concret (sa valeur pourrait être d'un type dérivé). Le couplage ici est minime.
Considérons maintenant var x = A?.B?.C?.D?.E?.F
.
Ce qui signifie que A
doit être d'un type qui pourrait être nul, ou pourrait avoir une propriété B
, qui doit être d'un type qui pourrait être nul ou avoir un C
, et ainsi de suite jusqu'à ce que le type de la propriété E
soit quelque chose qui puisse être nul ou avoir une propriété F
.
En d'autres termes, nous devons le faire avec un langage à typage statique ou avoir appliqué une contrainte sur les types qui peuvent être renvoyés si le typage est lâche. Dans la plupart des cas, C # utilise le typage statique, nous n'avons donc rien changé.
Si nous avions alors le code suivant violerait également la loi:
ExplicitType x;
var b = A.B;
if (b == null)
x = null;
else
{
var c = b.C;
if (c == null)
x = null;
else
{
var d = c.D;
if (d == null)
x = null;
else
{
var e = d.E;
if (e == null)
x = null;
else
x = e.F;
}
}
}
Ce qui est exactement le même. Ce code qui utilise le couplage de différents éléments doit "connaître" la chaîne complète de couplage, mais il utilise un code qui ne viole pas la loi de Déméter pour ce faire, chaque unité ayant un couplage bien défini avec la suivante.
L'objet peut être créé dans le but d'encapsuler des comportements ou de conserver des données, et des objets peuvent être créés dans le but d'être partagés avec du code extérieur ou détenus en privé par leur créateur.
Les objets qui sont créés dans le but d'encapsuler un comportement (qu'ils soient partagés ou non), ou pour être partagés avec du code extérieur (qu'ils encapsulent un comportement ou des données) doivent généralement être accessibles via leur interface de surface. Cependant, lorsque des objets contenant des données sont créés pour être utilisés exclusivement par leur créateur, les raisons normales de la loi de Demeter pour éviter un accès "profond" ne s'appliquent pas. Si une partie d'une classe qui stocke ou manipule des données dans l'objet est modifiée d'une manière qui nécessiterait l'ajustement d'un autre code, il sera possible de garantir que tout ce code est mis à jour car - comme indiqué ci-dessus - l'objet a été créé pour l'utilisation exclusive d'une classe.
Alors que je pense que le?. L'opérateur aurait peut-être pu être mieux conçu, il y a suffisamment de situations où les objets utilisent des structures de données imbriquées que l'opérateur a de nombreux cas d'utilisation qui ne violeraient pas les principes exprimés par la loi de Demeter. Le fait qu'il puisse être utilisé pour violer la LoD ne doit pas être considéré comme un argument contre l'opérateur, car il n'est pas pire que le "." opérateur à cet égard.