La interfaz fluida ( Interfaz fluida en inglés - en el sentido de "interfaz" "suave" o "suave") en el desarrollo de software es una forma de implementar una API orientada a objetos , destinada a aumentar la legibilidad del código fuente del programa. Nombre acuñado por Eric Evans y Martin Fowler .
La ventaja de una interfaz fluida es que facilita llamar a varios métodos en el mismo objeto. Esto generalmente se implementa mediante una cadena de métodos que pasa el contexto de la llamada al siguiente salto (pero una interfaz fluida implica más que solo una cadena de métodos [1] ). Por lo general, este contexto:
Este estilo es indirectamente útil para aumentar la visibilidad y la intuición del código. . Sin embargo, la depuración puede ser bastante perjudicial si la cadena actúa como una declaración única en la que el depurador no siempre puede establecer un punto de interrupción intermedio .
El siguiente ejemplo muestra una clase normal y una clase que implementa una interfaz fluida y las diferencias de uso. El ejemplo está escrito en Delphi Object Pascal:
unidad FluentInterface ; interfaz escriba IConfiguration = procedimiento de interfaz SetColor ( Color : cadena ) ; procedimiento SetHeight ( altura : entero ) ; procedimiento SetLength ( longitud : entero ) ; procedimiento SetDepth ( profundidad : entero ) ; fin ; IConfigurationFluent = función de interfaz SetColor ( Color : cadena ) : IConfigurationFluent ; función SetHeight ( altura : entero ) : IConfigurationFluent ; función SetLength ( longitud : entero ) : IConfigurationFluent ; función SetDepth ( profundidad : entero ) : IConfigurationFluent ; fin ; TConfiguration = class ( TInterfacedObject , IConfiguration ) private FColor : string ; FAltura : entero ; FLongitud : entero ; FDepth : entero ; procedimiento protegido SetColor ( Color : cadena ) ; procedimiento SetHeight ( altura : entero ) ; procedimiento SetLength ( longitud : entero ) ; procedimiento SetDepth ( profundidad : entero ) ; fin ; TConfigurationFluent = clase ( TInterfacedObject , IConfigurationFluent ) private FColor : string ; FAltura : entero ; FLongitud : entero ; FDepth : entero ; función protegida SetColor ( Color : cadena ) : IConfigurationFluent ; función SetHeight ( altura : entero ) : IConfigurationFluent ; función SetLength ( longitud : entero ) : IConfigurationFluent ; función SetDepth ( profundidad : entero ) : IConfigurationFluent ; función de clase pública Nuevo : IConfigurationFluent ; fin ; implementación procedimiento TConfiguración . SetColor ( Color : cadena ) ; comenzar FColor := Color ; fin ; procedimiento TConfiguración . SetDepth ( profundidad : entero ) ; comenzar FDepth := profundidad ; fin ; procedimiento TConfiguración . SetHeight ( altura : entero ) ; comenzar FAltura := altura ; fin ; procedimiento TConfiguración . SetLength ( longitud : entero ) ; comenzar FLength := longitud ; fin ; función de clase TConfigurationFluent . Nuevo : IConfigurationFluent ; comenzar Resultado := Crear ; fin ; función TConfigurationFluent . SetColor ( Color : cadena ) : IConfigurationFluent ; comenzar FColor := Color ; Resultado := Yo ; fin ; función TConfigurationFluent . SetDepth ( profundidad : entero ) : IConfigurationFluent ; comenzar FDepth := profundidad ; Resultado := Yo ; fin ; función TConfigurationFluent . SetHeight ( altura : entero ) : IConfigurationFluent ; comenzar FAltura := altura ; Resultado := Yo ; fin ; función TConfigurationFluent . SetLength ( longitud : entero ) : IConfigurationFluent ; comenzar FLength := longitud ; Resultado := Yo ; fin ; fin _ var C , D : IConfiguración ; E : Configuración fluida ; comenzar { Uso común:} C := TConfiguration . crear ; c._ _ EstablecerColor ( 'azul' ) ; c._ _ Establecer Altura ( 1 ) ; c._ _ EstablecerLongitud ( 2 ) ; c._ _ EstablecerProfundidad ( 3 ) ; { implementación regular, simplificada con la sentencia with } D := TConfiguration . crear ; con D comience SetColor ( ' blue ' ) ; Establecer Altura ( 1 ) ; EstablecerLongitud ( 2 ) ; EstablecerProfundidad ( 3 ) end ; { usando la implementación de interfaz fluida } E := TConfigurationFluent . nuevo _ EstablecerColor ( 'Azul' ) . Establecer Altura ( 1 ) . EstablecerLongitud ( 2 ) . EstablecerProfundidad ( 3 ) ; fin ;Desde C# 3.5 en adelante, se han introducido formas avanzadas de implementar una interfaz fluida:
espacio de nombres Example.FluentInterfaces { #region Ejemplo estándar interfaz pública IConfiguration { string Color { set ; } int Altura { conjunto ; } longitud int { conjunto ; } int Profundidad { conjunto ; } } Configuración de clase pública : IConfiguration { string color ; altura int ; longitud int ; profundidad interna ; cadena pública Color { conjunto { color = valor ; } } public int Altura { set { altura = valor ; } } public int Longitud { set { longitud = valor ; } } public int Profundidad { set { profundidad = valor ; } } } #endregion #region Ejemplo fluido interfaz pública IConfigurationFluent { IConfigurationFluent SetColor ( color de cadena ); IConfigurationFluent SetHeight ( altura int ); IConfigurationFluent SetLength ( longitud int ); IConfigurationFluent SetDepth ( int profundidad ); } Clase pública ConfigurationFluent : IConfigurationFluent { string color ; altura int ; longitud int ; profundidad interna ; public IConfigurationFluent SetColor ( color de cadena ) { este . color = color ; devolver esto ; } public IConfigurationFluent SetHeight ( altura int ) { this . altura = altura ; devolver esto ; } public IConfigurationFluent SetLength ( longitud int ) { this . largo = largo ; devolver esto ; } public IConfigurationFluent SetDepth ( profundidad int ) { this . profundidad = profundidad ; devolver esto ; } } #endregion public class ExampleProgram { public static void Main ( string [] args ) { // Ejemplo típico IConfiguration config = new Configuration { Color = "blue" , Altura = 1 , Longitud = 2 , Profundidad = 3 }; // Ejemplo de interfaz fluida IConfigurationFluent fluentConfig = new ConfigurationFluent (). EstablecerColor ( "azul" ) . Establecer Altura ( 1 ) . EstablecerLongitud ( 2 ) . EstablecerProfundidad ( 3 ); } } }Un ejemplo común en C++ es el estándar iostream , donde la fluidez es proporcionada por la sobrecarga del operador .
Ejemplo de contenedor de interfaz fluida en C++:
// clase de trabajo normal GlutApp { privado : int w_ , h_ , x_ , y_ , argc_ , display_mode_ ; char ** argv_ ; char * titulo_ ; público : GlutApp ( int argc , char ** argv ) { argc_ = argc ; argv_ = argv ; } void setDisplayMode ( modo int ) { display_mode_ = modo ; } int getDisplayMode () { volver modo_visualización_ ; } void setWindowSize ( int w , int h ) { w_ = w ; h_ = h ; } void setWindowPosition ( int x , int y ) { x_ = x ; y_ = y ; } void setTitle ( const char * title ) { titulo_ = titulo ; } vacío crear (); }; // uso normal int main ( int argc , char ** argv ) { Aplicación GlutApp ( argc , argv ) ; aplicación _ establecer Modo de visualización ( GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH ); // Establecer la aplicación de parámetros de framebuffer . establecerTamañoVentana ( 500 , 500 ); // Establecer aplicación de parámetros de ventana . establecer PosiciónVentana ( 200 , 200 ); aplicación _ setTitle ( "Mi aplicación OpenGL/GLUT" ); aplicación _ crear (); } // Clase contenedora de interfaz fluida FluentGlutApp : private GlutApp { público : FluentGlutApp ( int argc , char ** argv ) : GlutApp ( argc , argv ) {} // hereda el constructor padre FluentGlutApp & withDoubleBuffer () { setDisplayMode ( getDisplayMode () | GLUT_DOUBLE ); devolver * esto ; } FluentGlutApp y conRGBA () { setDisplayMode ( getDisplayMode () | GLUT_RGBA ); devolver * esto ; } FluentGlutApp y withAlpha () { setDisplayMode ( getDisplayMode () | GLUT_ALPHA ); devolver * esto ; } FluentGlutApp y con profundidad () { setDisplayMode ( getDisplayMode () | GLUT_DEPTH ); devolver * esto ; } FluentGlutApp y a través ( int w , int h ) { establecerTamañoVentana ( w , h ); devolver * esto ; } FluentGlutApp & en ( int x , int y ) { establecer PosiciónVentana ( x , y ); devolver * esto ; } FluentGlutApp & named ( const char * title ) { establecerTitulo ( titulo ); devolver * esto ; } // no importa si encadenamos después de la llamada a create(), por lo que no devolvemos *this void create () { GlutApp :: crear (); } }; // usa la interfaz fluida int main ( int argc , char ** argv ) { Aplicación FluentGlutApp ( argc , argv ) . con DoubleBuffer (). con RGBA (). con Alfa (). conProfundidad () . en ( 200 , 200 ). de ancho ( 500 , 500 ) . named ( "Mi aplicación OpenGL/GLUT" ); aplicación _ crear (); }Algunas API en Java implementan una interfaz de este tipo, como la API de persistencia de Java :
public Collection < Estudiante > findByNameAgeGender ( String name , int age , Gender gender ) { return em . createNamedQuery ( "Estudiante.findByNameAgeGender" ) . setParameter ( "nombre" , nombre ) . setParameter ( "edad" , edad ) . setParameter ( "género" , género ) . establecerPrimerResultado ( 1 ) . establecerResultadosMax ( 30 ) . setHint ( "nombrePista" , "ValorPista" ) . obtenerListaResultados (); }La biblioteca op4j le permite usar una interfaz fluida para realizar tareas auxiliares como iterar estructuras , convertir información, filtrar, etc.
String [] dateStr = new String [] { "10-12-1492" , "12-06-1978" }; ... Lista < Calendario > fechas = Op . el ( fechasStr ). aLista (). mapa ( FnString . toCalendar ( "dd-MM-yyyy" )). obtener ();Además, la biblioteca EasyMock Test Object Mock hace un uso extensivo de este estilo para proporcionar una interfaz fácil de usar.
Colección mockCollection = EasyMock . createMock ( Colección . Clase ); EasyMock . esperar ( mockCollection . eliminar ( null )). andThrow ( nueva NullPointerException ()). al menos una vez ();Un ejemplo de una implementación de clase con una interfaz fluida en PHP :
clase Coche { privado $velocidad , $color , $puertas ; public function setSpeed ( $velocidad ){ $esto -> velocidad = $velocidad ; devolver $esto ; } public function setColor ( $color ) { $this -> color = $color ; devolver $esto ; } public function establecerPuertas ( $puertas ) { $esto -> puertas = $puertas ; devolver $esto ; } } // Implementación habitual $myCar2 = new Car (); $myCar2 - > establecerVelocidad ( 100 ); $myCar2 -> setColor ( 'azul' ); $myCar2 - > establecerPuertas ( 5 ); // Interfaz fluida $myCar = new Car (); $myCar -> setSpeed ( 100 ) -> setColor ( 'blue' ) -> setDoors ( 5 );Un ejemplo de una implementación de clase con una interfaz fluida en JavaScript :
varCar = ( función ( ){ var velocidad , color , puertas , pub ; function setSpeed ( nueva_velocidad ) { velocidad = nueva_velocidad ; pub de vuelta ; } función setColor ( nuevo_color ) { color = nuevo_color ; pub de vuelta ; } function establecerPuertas ( nuevas_puertas ) { puertas = nuevas_puertas ; pub de vuelta ; } pub = { 'establecerVelocidad' : establecerVelocidad , 'establecerColor' : establecerColor , 'establecerPuertas' : establecerPuertas , }; pub de vuelta ; }) // Implementación normal myCar2 = Car (); miCoche2 . establecerVelocidad ( 100 ); miCoche2 . setColor ( 'azul' ); miCoche2 . establecerPuertas ( 5 ); // Interfaz actual myCar = Car (); miCoche . establecerVelocidad ( 100 ). setColor ( 'azul' ). establecerPuertas ( 5 );También puede utilizar otro enfoque:
var $ = function ( selector ) { if ( this . $ ) { return new $ ( selector ); } if ( tipo de selector == "cadena" ) { esto . init = documento . getElementById ( selector ); } }; $ . prototipo = { texto : función ( texto ) { si ( ! texto ){ esto . inicializar _ HTML interno ; } esto . inicializar _ HTML interno = texto ; devolver esto ; }, css : función ( estilo ) { para ( var i en estilo ){ esto . inicializar _ estilo [ i ] = estilo [ i ]; } devuelve esto ; } }; //ejemplo de uso: $ ( 'div' ). texto ( 'div' ). css ({ color : "rojo" });Un ejemplo de una implementación independiente del tipo del objeto devuelto:
({ foo : function ( a ) { return a ; } }). foo ( 'foo' ). a Mayúsculas ();Patrones de diseño | |
---|---|
Principal | |
Generativo | |
Estructural | |
conductual | |
Programación en paralelo |
|
arquitectónico |
|
Plantillas Java EE | |
Otras plantillas | |
Libros | |
Alusiones personales |