Cuando usar el encadenamiento
El encadenamiento de funciones es muy popular en los idiomas en los que un IDE con autocompletar es un lugar común. Por ejemplo, casi todos los desarrolladores de C # usan Visual Studio. Por lo tanto, si está desarrollando con C #, agregar encadenamiento a sus métodos puede ser un ahorro de tiempo para los usuarios de esa clase porque Visual Studio lo ayudará a construir la cadena.
Por otro lado, los lenguajes como PHP que son de naturaleza altamente dinámica y que a menudo no tienen soporte de autocompletar en IDEs verán menos clases que admitan el encadenamiento. El encadenamiento solo será apropiado cuando se empleen los phpDoc correctos para exponer los métodos encadenables.
¿Qué es el encadenamiento?
Dada una clase llamada Foo
los siguientes dos métodos son ambos encadenables.
function what() { return this; }
function when() { return new Foo(this); }
El hecho de que uno sea una referencia a la instancia actual y cree una nueva instancia no cambia que estos son métodos encadenables.
No existe una regla de oro de que un método encadenable solo debe hacer referencia al objeto actual. De hecho, los métodos encadenables pueden ser a través de dos clases diferentes. Por ejemplo;
class B { function When() { return true; } };
class A { function What() { return new B(); } };
var a = new A();
var x = a.What().When();
No hay ninguna referencia a this
ninguno de los ejemplos anteriores. El código a.What().When()
es un ejemplo de encadenamiento. Lo interesante es que el tipo de clase B
nunca se asigna a una variable.
Un método se encadena cuando su valor de retorno se utiliza como el siguiente componente de una expresión.
Aquí hay un ejemplo más
// 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();
Cuando usar this
ynew(this)
Las cadenas en la mayoría de los idiomas son inmutables. Por lo tanto, las llamadas a métodos de encadenamiento siempre generan nuevas cadenas. Donde como un objeto como StringBuilder se puede modificar.
La consistencia es la mejor práctica.
Si tiene métodos que modifican el estado de un objeto y lo devuelven this
, no mezcle métodos que devuelvan nuevas instancias. En su lugar, cree un método específico llamado Clone()
que haga esto explícitamente.
var x = a.Foo().Boo().Clone().Foo();
Eso es mucho más claro en cuanto a lo que está sucediendo dentro a
.
El paso afuera y el truco de vuelta
A esto lo llamo el truco de salida y retroceso , porque resuelve muchos problemas comunes relacionados con el encadenamiento. Básicamente significa que sales de la clase original a una nueva clase temporal y luego regresas a la clase original.
La clase temporal existe solo para proporcionar características especiales a la clase original, pero solo bajo condiciones especiales.
A menudo hay momentos en que una cadena necesita cambiar de estado , pero la clase A
no puede representar todos esos estados posibles . Entonces, durante una cadena, se introduce una nueva clase que contiene una referencia a A
. Esto permite al programador entrar en un estado y volver a A
.
Aquí está mi ejemplo, que el estado especial se conozca como 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();
Ahora ese es un ejemplo muy simple. Si quisieras tener más control, entonces B
podrías volver a un nuevo supertipo A
que tenga métodos diferentes.