Quand utiliser le chaînage
Le chaînage de fonctions est surtout populaire dans les langues où un IDE avec auto-complétion est courant. Par exemple, presque tous les développeurs C # utilisent Visual Studio. Par conséquent, si vous développez avec C #, l'ajout de chaînage à vos méthodes peut être un gain de temps pour les utilisateurs de cette classe, car Visual Studio vous aidera à créer la chaîne.
D'un autre côté, les langages comme PHP qui sont de nature très dynamique et qui ne prennent souvent pas en charge la saisie semi-automatique dans les IDE verront moins de classes qui prennent en charge le chaînage. Le chaînage ne sera approprié que lorsque des phpDocs corrects sont utilisés pour exposer les méthodes chaînables.
Qu'est-ce que le chaînage?
Étant donné une classe nommée, Foo
les deux méthodes suivantes sont toutes deux chaînables.
function what() { return this; }
function when() { return new Foo(this); }
Le fait que l'on soit une référence à l'instance actuelle et que l'on crée une nouvelle instance ne change pas qu'il s'agit de méthodes chaînables.
Il n'y a pas de règle d'or selon laquelle une méthode chaînable doit uniquement référencer l'objet actuel. En fait, les méthodes chaînables peuvent être réparties sur deux classes différentes. Par exemple;
class B { function When() { return true; } };
class A { function What() { return new B(); } };
var a = new A();
var x = a.What().When();
Il n'y a aucune référence à this
dans aucun des exemples ci-dessus. Le code a.What().When()
est un exemple de chaînage. Ce qui est intéressant, c'est que le type de classe B
n'est jamais affecté à une variable.
Une méthode est enchaînée lorsque sa valeur de retour est utilisée comme composant suivant d'une expression.
Voici un autre exemple
// return value never assigned.
myFile.Open("something.txt").Write("stuff").Close();
// two chains used in expression
int x = a.X().Y() * b.X().Y();
// a chain that creates new strings
string name = str.Substring(1,10).Trim().ToUpperCase();
Quand utiliser this
etnew(this)
Les cordes dans la plupart des langues sont immuables. Le chaînage d'appels de méthode entraîne donc toujours la création de nouvelles chaînes. Où un objet comme StringBuilder peut être modifié.
La cohérence est la meilleure pratique.
Si vous avez des méthodes qui modifient l'état d'un objet et retournent this
, ne mélangez pas les méthodes qui retournent de nouvelles instances. Au lieu de cela, créez une méthode spécifique appelée Clone()
qui le fera explicitement.
var x = a.Foo().Boo().Clone().Foo();
C'est beaucoup plus clair sur ce qui se passe à l'intérieur a
.
L'étape de l'extérieur et du dos
J'appelle cela l' astuce aller-retour , car elle résout beaucoup de problèmes courants liés au chaînage. Cela signifie essentiellement que vous sortez de la classe d'origine pour entrer dans une nouvelle classe temporaire, puis revenez à la classe d'origine.
La classe temporaire existe uniquement pour fournir des fonctionnalités spéciales à la classe d'origine, mais uniquement dans des conditions spéciales.
Il y a souvent des moments où une chaîne doit changer d' état , mais la classe A
ne peut pas représenter tous ces états possibles . Ainsi, au cours d'une chaîne, une nouvelle classe est introduite qui contient une référence à A
. Cela permet au programmeur de passer à un état et de revenir à A
.
Voici mon exemple, que l'état spécial soit appelé B
.
class A {
function Foo() { return this; }
function Boo() { return this; }
function Change() return new B(this); }
}
class B {
var _a;
function (A) { _a = A; }
function What() { return this; }
function When() { return this; }
function End() { return _a; }
}
var a = new A();
a.Foo().Change().What().When().End().Boo();
Voilà un exemple très simple. Si vous vouliez avoir plus de contrôle, vous B
pourriez revenir à un nouveau super-type A
qui a différentes méthodes.
return this
. Comment puis-je aider les utilisateurs de mes bibliothèques à gérer et à comprendre cette situation? (Les autoriser à enchaîner les méthodes, même si ce n'est pas nécessaire, serait-ce vraiment correct? Ou devrais-je m'en tenir à une seule façon, exiger un changement?)Selon la langue, avoir des méthodes qui retournent
void
/unit
et modifient leur instance ou leurs paramètres n'est pas idiomatique. Même dans les langages qui en faisaient plus (C #, C ++), il se démode avec le passage à une programmation de style plus fonctionnelle (objets immuables, fonctions pures). Mais supposons qu'il y ait une bonne raison pour l'instant.Pour certains comportements (pensez
x++
), on s'attend à ce que l'opération renvoie le résultat, même si elle modifie la variable. Mais c'est en grande partie la seule raison de le faire par vous-même.Ça dépend.
Dans les langues où copy / new et return sont communs (C # LINQ et chaînes), renvoyer la même référence serait source de confusion. Dans les langues où la modification et le retour sont courants (certaines bibliothèques C ++), la copie serait source de confusion.
Rendre la signature sans ambiguïté (en retournant
void
ou en utilisant des constructions de langage comme des propriétés) serait la meilleure façon de clarifier. Après cela, clarifier le nomSetFoo
pour montrer que vous modifiez l'instance existante est bon. Mais la clé est de maintenir les idiomes de la langue / bibliothèque avec laquelle vous travaillez.la source
Clear()
ouAdd()
de tout type de collection modifieront la même instance et retournerontvoid
. Dans les deux cas, vous dites que ce serait déroutant ...obj = myCollection.Where(x => x.MyProperty > 0).OrderBy(x => x.MyProperty);
alors?Where()
renvoie un nouvel objet de collection.OrderBy()
renvoie même un objet de collection différent, car le contenu est ordonné.IEnumerable
, mais pour être clair, ils ne sont pas des copies, et ils ne sont pas des collections (saufToList
,ToArray
etc.).ICollection
. Ma faute.(J'ai supposé C ++ comme langage de programmation)
Pour moi, c'est surtout un aspect de lisibilité. Si A, B, C sont des modificateurs, en particulier s'il s'agit d'un objet temporaire passé en paramètre à une fonction, par exemple
par rapport à
Reclassement s'il est correct de renvoyer une référence à l'instance modifiée, je dirais oui, et je vous pointe par exemple vers les opérateurs de flux '>>' et '<<' ( http://www.cprogramming.com/tutorial/ operator_overloading.html )
la source
Vous pouvez également faire le chaînage de méthode avec le retour de copie plutôt que de modifier le retour.
Un bon exemple en C # est string.Replace (a, b) qui ne change pas la chaîne sur laquelle il a été invoqué mais renvoie à la place une nouvelle chaîne vous permettant de chaîner joyeusement.
la source