Flytande gränssnitt

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 20 februari 2016; kontroller kräver 7 redigeringar .

Flytande gränssnitt ( engelska  fluent interface  - i betydelsen "smooth" eller "smooth" "interface") i  mjukvaruutveckling  är ett sätt att implementera ett objektorienterat  API , som syftar till att öka läsbarheten av programmets källkod. Namn myntad av Eric Evans och  Martin Fowler .

Fördelen med ett flytande gränssnitt är att det gör det lättare att anropa flera metoder på samma objekt. Detta implementeras vanligtvis med hjälp av en metodkedja som skickar sammanhanget för anropet till nästa hopp (men ett flytande gränssnitt innebär mer än bara en metodkedja [1] ). Vanligtvis är detta sammanhang:

Denna stil är indirekt användbar för att öka kodens synlighet och intuitivitet. . Men felsökning kan vara ganska skadligt om kedjan fungerar som en enda sats där felsökaren inte alltid kan ställa in en mellanliggande brytpunkt .

Exempel

Delphi (Objekt Pascal)

Följande exempel visar en vanlig klass och en klass som implementerar ett flytande gränssnitt och skillnaderna i användning. Exemplet är skrivet i Delphi Object Pascal:

enhet FluentInterface ; gränssnitt typ IConfiguration = gränssnittsprocedur SetColor ( Färg : sträng ) ; _ procedure SetHeight ( höjd : heltal ) ; procedure SetLength ( längd : heltal ) ; procedure SetDepth ( djup : heltal ) ; slut ; IConfigurationFluent = gränssnittsfunktion SetColor ( Färg : sträng ) : IConfigurationFluent ; _ funktion SetHeight ( höjd : heltal ) : IConfigurationFluent ; function SetLength ( längd : heltal ) : IConfigurationFluent ; funktion SetDepth ( djup : heltal ) : IConfigurationFluent ; slut ; TConfiguration = klass ( TInterfacedObject , IConfiguration ) privat FColor : string ; FHöjd : heltal ; FLängd : heltal ; FDepth : heltal ; skyddad procedur SetColor ( Color : string ) ; procedure SetHeight ( höjd : heltal ) ; procedure SetLength ( längd : heltal ) ; procedure SetDepth ( djup : heltal ) ; slut ; TConfigurationFluent = klass ( TInterfacedObject , IConfigurationFluent ) privat FColor : string ; FHöjd : heltal ; FLängd : heltal ; FDepth : heltal ; skyddad funktion SetColor ( Color : string ) : IConfigurationFluent ; funktion SetHeight ( höjd : heltal ) : IConfigurationFluent ; function SetLength ( längd : heltal ) : IConfigurationFluent ; funktion SetDepth ( djup : heltal ) : IConfigurationFluent ; public class funktion Nytt : IConfigurationFluent ; slut ; genomförande procedur TConfiguration . SetColor ( Färg : sträng ) ; börja FColor := Färg ; slut ; procedur TConfiguration . SetDepth ( djup : heltal ) ; börja FDepth := depth ; slut ; procedur TConfiguration . SetHeight ( höjd : heltal ) ; börja FHöjd := höjd ; slut ; procedur TConfiguration . SetLength ( längd : heltal ) ; börja FLängd := längd ; slut ; klassfunktion TConfigurationFluent . _ Nytt : IConfigurationFluent ; börja Resultat := Skapa ; slut ; funktion TConfigurationFluent . SetColor ( Color : string ) : IConfigurationFluent ; börja FColor := Färg ; Resultat := Själv ; slut ; funktion TConfigurationFluent . SetDepth ( djup : heltal ) : IConfigurationFluent ; börja FDepth := depth ; Resultat := Själv ; slut ; funktion TConfigurationFluent . SetHeight ( höjd : heltal ) : IConfigurationFluent ; börja FHöjd := höjd ; Resultat := Själv ; slut ; funktion TConfigurationFluent . SetLength ( längd : heltal ) : IConfigurationFluent ; börja FLängd := längd ; Resultat := Själv ; slut ; slut . var C , D : IConfiguration ; E : IConfiguration Fluent ; börja { Common usage:} C := TConfiguration . skapa ; C. _ SetColor ( 'blå' ) ; C. _ SetHeight ( 1 ) ; C. _ SetLength ( 2 ) ; C. _ SetDepth ( 3 ) ; { regelbunden implementering, förenklad med med-satsen } D := TConfiguration . skapa ; med D börjar SetColor ( ' blå' ) ; SetHeight ( 1 ) ; SetLength ( 2 ) ; SetDepth ( 3 ) slut ; { using fluent interface implementation } E := TConfigurationFluent . Nytt . SetColor ( 'Blå' ) . SetHeight ( 1 ) . SetLength ( 2 ) . SetDepth ( 3 ) ; slut ;

C#

Från C# 3.5 och framåt har avancerade sätt att implementera ett flytande gränssnitt introducerats:

namnområde Exempel.Flytande gränssnitt { #region Standardexempel offentligt gränssnitt IConfiguration { sträng Färg { set ; } int Höjd { set ; } int length { set ; } int Depth { set ; } } public class Konfiguration : IConfiguration { string color ; int höjd ; int längd ; int djup ; public string Color { set { color = value ; } } public int Height { set { höjd = värde ; } } public int Length { set { length = value ; } } public int Depth { set { depth = värde ; } } } #ändregion #region Flytande Exempel offentligt gränssnitt IConfigurationFluent { IConfigurationFluent SetColor ( strängfärg ) ; IConfigurationFluent SetHeight ( int höjd ); IConfigurationFluent SetLength ( int längd ); IConfigurationFluent SetDepth ( int depth ); } public class ConfigurationFluent : IConfigurationFluent { string color ; int höjd ; int längd ; int djup ; public IConfigurationFluent SetColor ( strängfärg ) { detta . _ färg = färg ; returnera detta ; } public IConfigurationFluent SetHeight ( int height ) { this . höjd = höjd ; returnera detta ; } public IConfigurationFluent SetLength ( int length ) { this . längd = längd ; returnera detta ; } public IConfigurationFluent SetDepth ( int depth ) { detta . djup = djup ; returnera detta ; } } #ändregion public class ExempelProgram { public static void Main ( string [] args ) { // Typiskt exempel IConfiguration config = new Configuration { Color = "blue" , ​​​​Height = 1 , Length = 2 , Depth = 3 }; // Exempel på flytande gränssnitt IConfigurationFluent fluentConfig = new ConfigurationFluent (). SetColor ( "blå" ) . SetHeight ( 1 ) . SetLength ( 2 ) . SetDepth ( 3 ); } } }

C++

Ett vanligt exempel i C++  är standard iostream , där fluiditet tillhandahålls av operatörens överbelastning .

Exempel på vätskegränssnitt i C ++:

// normal jobbklass GlutApp { privat : int w_ , h_ , x_ , y_ , argc_ , display_mode_ ; char ** argv_ ; char * title_ ; offentliga : GlutApp ( int argc , char ** argv ) { argc_ = argc ; argv_ = argv ; } void setDisplayMode ( int mode ) { display_mode_ = läge ; } int getDisplayMode () { returnera display_mode_ ; } 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 ) { title_ = titel ; } void skapa (); }; // normal användning int main ( int argc , char ** argv ) { GlutApp- app ( argc , argv ); app . setDisplayMode ( GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH ); // Ställ in framebuffer params app . setWindowSize ( 500 , 500 ); // Ställ in fönstret params app . setWindowPosition ( 200 , 200 ); app . setTitle ( "Min OpenGL/GLUT-app" ); app . skapa (); } // Fluent interface wrapper class FluentGlutApp : privat GlutApp { offentliga : FluentGlutApp ( int argc , char ** argv ) : GlutApp ( argc , argv ) {} // ärv den överordnade konstruktorn FluentGlutApp & withDoubleBuffer () { setDisplayMode ( getDisplayMode () | GLUT_DOUBLE ); returnera * detta ; } FluentGlutApp & withRGBA () { setDisplayMode ( getDisplayMode () | GLUT_RGBA ); returnera * detta ; } FluentGlutApp & withAlpha () { setDisplayMode ( getDisplayMode () | GLUT_ALPHA ); returnera * detta ; } FluentGlutApp & withDepth () { setDisplayMode ( getDisplayMode () | GLUT_DEPTH ); returnera * detta ; } FluentGlutApp & tvärsöver ( int w , int h ) { setWindowSize ( w , h ); returnera * detta ; } FluentGlutApp & at ( int x , int y ) { setWindowPosition ( x , y ); returnera * detta ; } FluentGlutApp & namngiven ( const char * title ) { setTitle ( titel ); returnera * detta ; } // det spelar ingen roll om vi kedjar efter create()-anropet, så vi returnerar inte *this void create () { GlutApp :: skapa (); } }; // använd flytande gränssnitt int main ( int argc , char ** argv ) { FluentGlutApp app ( argc , argv ) . withDoubleBuffer (). medRGBA (). med Alpha (). med djup () . vid ( 200 , 200 ). tvärsöver ( 500 , 500 ) . heter ( "Min OpenGL/GLUT-app" ); app . skapa (); }

Java

Vissa API:er i Java implementerar ett sådant gränssnitt, till exempel Java Persistence API :

public Collection < Student > findByNameAgeGender ( String name , int age , Gender gender ) { return em . createNamedQuery ( "Student.findByNameAgeGender" ) . setParameter ( "namn" , namn ) . setParameter ( "ålder" , ålder ) . setParameter ( "kön" , kön ) . setFirstResult ( 1 ) . setMaxResults ( 30 ) . setHint ( "hintName" , "hintValue" ) . getResultList (); }

Op4j - biblioteket låter dig använda ett flytande gränssnitt för att utföra extra uppgifter som iterering av strukturer , konvertering av information, filtrering, etc.

String [] datesStr = ny String [] { "12-10-1492" , "06-12-1978" }; ... Lista < Kalender > datum = Op . ( datesStr ). toList (). map ( FnString . toCalendar ( "dd-MM-åååå" )). ();

Dessutom använder EasyMock Test Object Mock -biblioteket i stor utsträckning denna stil för att ge ett användarvänligt gränssnitt.

Samling mockCollection = EasyMock . createMock ( Collection . class ); EasyMock . förvänta ( mockCollection . ta bort ( null )). andThrow ( ny NullPointerException ()). åtminstone en gång ();

PHP

Ett exempel på en klassimplementering med ett flytande gränssnitt i PHP :

klass Bil { privat $hastighet , $färg , $dörrar ; public function setSpeed ​​​​( $speed ){ $this -> speed = $speed ; returnera $detta ; } public function setColor ( $color ) { $this -> color = $color ; returnera $detta ; } public function setDoors ( $doors ) { $this -> doors = $doors ; returnera $detta ; } } // Vanlig implementering $myCar2 = ny bil (); $myCar2 -> setSpeed ​​( 100 ); $myCar2 -> setColor ( 'blå' ); $myCar2 -> setDoors ( 5 ); // Vätskegränssnitt $myCar = ny bil (); $myCar -> setSpeed ​​​​( 100 ) -> setColor ( 'blå' ) -> setDoors ( 5 );

JavaScript

Ett exempel på en klassimplementering med ett flytande gränssnitt i JavaScript :

varCar = ( funktion ( ){ var hastighet , färg , dörrar , pub ; function setSpeed ​​​​( new_speed ) { speed = new_speed ; återvända pub ; } function setColor ( new_color ) { color = new_color ; återvända pub ; } function setDoors ( nya_dörrar ) { dörrar = nya_dörrar ; återvända pub ; } pub = { 'setSpeed' : setSpeed , 'setColor' : setColor , 'setDoors' : setDoors , }; återvända pub ; }) // Normal implementering myCar2 = Bil (); min bil 2 . setSpeed ​​( 100 ); min bil 2 . setColor ( 'blå' ); min bil 2 . setDörrar ( 5 ); // Nuvarande gränssnitt myCar = Bil (); min bil . setSpeed ​​( 100 ). setColor ( 'blå' ). setDörrar ( 5 );

Du kan också använda ett annat tillvägagångssätt:

var $ = funktion ( väljare ) { if ( detta . $ ) { returnera ny $ ( väljare ); } if ( väljartyp == "sträng " ) { detta . init = dokument . getElementById ( väljare ); } }; $ . prototyp = { text : function ( text ) { if ( ! text ) { this . init . innerHTML ; } detta . init . innerHTML = text ; returnera detta ; }, css : function ( stil ) { for ( vari i stil ) { detta . init . stil [ i ] = stil [ i ]; } returnera detta ; } }; //användningsexempel: $ ( 'div' ). text ( 'div' ). css ({ färg : "röd" });

Ett exempel på en typoberoende implementering av det returnerade objektet:

({ foo : function ( a ) { return a ; } }). foo ( 'foo' ). toUpperCase ();

Anteckningar

  1. MF Bliki: FluentInterface . Hämtad 26 oktober 2010. Arkiverad från originalet 8 mars 2021.

Länkar