método de nomenclatura
interfaces fluidas se prestan a la legibilidad siempre que los nombres de los métodos se elijan con sensatez.
Con esto en mente, me gustaría nominar a esta API en particular como "anti-fluidez":
System.Type.IsInstanceOfType
Es un miembro del System.Type
y toma un objeto y devuelve true si el objeto es una instancia del tipo.Por desgracia, que, naturalmente, tienden a leer de izquierda a derecha como esto:
o.IsInstanceOfType(t); // wrong
Cuando en realidad es a la inversa:
t.IsInstanceOfType(o); // right, but counter-intuitive
Pero no todos los métodos posiblemente podrían ser nombrados (o posicionados en el BCL) para anticipar cómo podrían aparecer en el código "pseudo-inglés", por lo que esto no es realmente una crítica. Solo estoy señalando otro aspecto de las interfaces fluidas: la elección de los nombres de los métodos para causar la menor sorpresa.
inicializadores de objeto
Con muchos de los ejemplos dados aquí, la única razón se utiliza una interfaz fluida es para que varias propiedades de un objeto recién asignada se pueden inicializar dentro de una sola expresión.
Pero C# tiene una característica del lenguaje que muy a menudo que ello resulte innecesario - objeto sintaxis de inicializador:
var myObj = new MyClass
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
};
Esto tal vez explicaría por qué experto en C# usuarios están menos familiarizados con el término "interfaz fluida" para encadenar las llamadas de el mismo objeto - no se necesita tan a menudo en C#.
Como las propiedades pueden tener adaptadores codificados a mano, esta es una oportunidad para invocar varios métodos en el objeto recién construido, sin tener que hacer que cada método devuelva el mismo objeto.
Las limitaciones son:
- Un colocador propiedad sólo puede aceptar un argumento
- Un colocador propiedad no puede ser genérico
me gustaría que pudiéramos llamar a los métodos y dar de alta en los eventos , así como asignar propiedades, dentro de un bloque de inicializador de objetos.
var myObj = new MyClass
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething()
Click += (se, ev) => MessageBox.Show("Clicked!"),
};
¿Y por qué un bloque de modificaciones solo debería aplicarse inmediatamente después de la construcción? Podríamos tener:
myObj with
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething(),
Click += (se, ev) => MessageBox.Show("Clicked!"),
}
El with
habría una nueva palabra clave que opera en un objeto de algún tipo y produce el mismo objeto y tipo - en cuenta que esto sería una expresión, no una declaración. Entonces capturaría exactamente la idea de encadenar en una "interfaz fluida".
De modo que podría usar sintaxis de estilo de inicializador independientemente de si obtuvo el objeto de una expresión new
o de un método IOC o de fábrica, etc.
De hecho, usted podría utilizar with
después de una completa new
y sería equivalente a la actual estilo de inicializador de objeto:
var myObj = new MyClass() with
{
SomeProperty = 5,
Another = true,
Complain = str => MessageBox.Show(str),
DoSomething(),
Click += (se, ev) => MessageBox.Show("Clicked!"),
};
Y como señala Charlie en los comentarios:
public static T With(this T with, Action<T> action)
{
if (with != null)
action(with);
return with;
}
El envoltorio anterior simplemente fuerza una acción no regresiva para devolver algo, y listo: cualquier cosa puede ser "fluida" en ese sentido.
Equivalente de inicializador, pero con el evento de reclutamiento:
var myObj = new MyClass().With(w =>
{
w.SomeProperty = 5;
w.Another = true;
w.Click += (se, ev) => MessageBox.Show("Clicked!");
};
Y en un método de fábrica en lugar de un new
:
var myObj = Factory.Alloc().With(w =>
{
w.SomeProperty = 5;
w.Another = true;
w.Click += (se, ev) => MessageBox.Show("Clicked!");
};
no pude resistir dándole el "tal vez mónada" - check de estilo para nulo también, por lo que si tiene algo que podría devolver null
, puede aplicarlo With
y luego verificarlo para null
-ness.
me gusta mucho patrón de FI. Acabo de publicar dos blogs en [lectura de datos para objetos de dominio] (http://davidchuprogramming.blogspot.com/2009/04/structuremap-and-fluent-interface.html). –
Una vez escribí una clase de colección que usaba indexadores para agregar a la colección que devolvía la instancia (de colección). El código parecía: 'myCollection [1] [2] [3] [4]' que es similar a 'new [] {1, 2, 3, 4}', por diversión: P – nawfal