Fluent interface

Kb. 2 éve olvastam először a fluent interface-ekről. Akkor nagyon megtetszett, és azóta is folyamatosan alkalmazom a módszert. Nem is gondoltam akkor, hogy Java-ban (vagy C#-ban) a legalapvetőbb nyelvi eszközökkel ilyen kifejező kódot lehet írni.

Az alapprobléma

Az eredeti probléma abban áll, hogy hogyan valósítsuk meg viszonylag sok paraméter átadását a kódban. A legalapvetőbb megoldás a standard módszer:

Jelen esetben 12 paraméter átadásáról van szó. Mondanom sem kell, hogy kínszevedés kliensként az ilyen metódust hívni, hiszen ahhoz, hogy tudjam, mit kell éppen átadni, az IDE-t kell segítségül hívnom. Ráadásul a keletkező kódot ilyen esetben borzasztó utólag is olvasni, hiszen nem rí le róla, hogy a híváskor milyen paraméterket, milyen sorrendben is adok át.

Martin Fowler Refactoring c. könyvében az Introduce Parameter Object c. minta próbál egyszerűsíteni a problémán, és azt javasolja, hogy rakjuk egy objektumba (osztályba) ezeket a paramétereket, majd ezt az objektumot adjuk át.


Sajnos, a gond még mindig ugyanaz, hiszen magát a RegistrationData típusú objektumot is fel kell töltenünk ugyanezekkel a paraméterekkel. Megoldás lenne a setter-ek alkalmazása, de őszintén szólva, ha ilyet meglátok a kódban, egy kisebb agyvérzést kapok. Mivel mások által sem javasolt az objektumok kívülről történő piszkálása (sérti az egységbezárás elvét), célszerű más megoldást keresni, és itt jönnek a fluent interface-ek a képbe.

A megoldás

Kliens oldalon a következő a használandó kód (pl. egy tesztben):


A RegistrationData osztály implementációja a következő:


A módszer előnye az, hogy amikor olvassuk a kódot, látszik, hogy a hívás pillanatában milyen paraméterek kapják a megfelelő értékeket. Ezért is kapta a fluent nevet a minta, hiszen folyamatosan, gondolkozás nélkül olvashatjuk a kódot, “folyékonyan”, mintha természetes nyelven lenne írva. 

Látható az is, hogy nem muszáj egy az egyben átkonvertálni minden paramétert egy with… hívássá, azok csoportosíthatóak nagyobb, jól nevesíthető tömbökbe. Például a firstName-et és lastName-et együtt a withName… metódussal olvassuk be. (Viszont egy ilyen with… hívásba sem szabad sok paramétert bezsúfolni, mert akkor ugyanott tartunk, ahonnan elindultunk.)

A módszer egyetlen hátránya, hogy – a standard, sokparaméteres átadással szemben – nem kényszeríti ki az összes paraméter átadását. Az eredeti példa pl. nem fordul addig, amíg át nem adunk 12 akármilyen paramétert (a típusoknak azért egyezniük kell). Ezt azzal szokták orvosolni, hogy a paraméterek átadása után hívnak egy validate()void visszatérési értékű metódust, amely elszáll, ha valamilyen paraméter nem lett kitöltve. Másik módszer a probléma megoldására, ha teszteket írunk. Amúgy – megsúgom – ha kihagyunk véletlenül egy paramétert, azt rövid időn belül úgyis észrevesszük, és korrigálhatunk, tehát nem célszerű emiatt túlságosan aggódni. Amit viszont cserébe kapunk, az a nagyfokú olvashatóság.

Share
This entry was posted in Programozás and tagged , . Bookmark the permalink. Follow any comments here with the RSS feed for this post. Post a comment or leave a trackback: Trackback URL.

Comments

  • Kristof Jozsa

    Jan 29th, 2010

    Nem szeretem.. igazad van hogy a fluent interface-n látszik, hogy melyik érték melyik propertyhez tartozik, csak pont azt nem kommunikálja hogy hányat kéne még megadni, így mindenképp doksit kell olvasnom, még az IDE sem segít. Egy standard konstruktor pont fordítva, de az legalább előtérbe tolja az encapsulationt és nem csinálhatsz félkész objektumot.. de vitatkozzunk :)

  • Kristof Jozsa

    Jan 29th, 2010

    ja és nyilván ha több alternatív konstruktor van akkor static factory method, ha még komplexebb a logika akkor factory..

  • Szerintem kimerítettük a témát :) Én a kódolvashatóságot tartom ebben az esetben az előtérben, dehát mindannyian mások vagyunk, és ez a szép :)

  • Egyszerűbb POJO-k inicializálására szerintem pont nem annyira jól használható, de pl. fastruktúrák kialakításához tökéletes. (ld. Hibernate Criteria API)

  • A saját projektünkben nem ritka, hogy 30-40 adatot is át kell tölteni. Ezekben az egyszerű adattípusokon kívül még tipikusan listák is szoktak szerepelni. (Szolgáltatás rétegről van szó.) Nekünk elég jól működik a fluent interface, és nem cserélném le másra.

    Másrészről a Hibernate-es dologra kitérve: én személy szerint nem szeretem használni a Hibernate Criteria API-t, mert nehezebb áttekinteni, hogy miről is szól a query. Ráadásul elég hamar performancia problémákba ütközik az ember, ha nagyobb adatmennyiséggel dolgozik, tehát a natív queryk egy idő után elkerülhetetlenné válnak.

    Az egyszerűbb queryk esetében használunk csupán HQL-t (és akkor is a sztringek direktben szerepelnek a kódban). Sok esetben az IntelliJ IDEA képes a sztringekben megfogalmazott queryket is refaktorálni. (Ha nem jönne össze, a tesztek meg úgyis elszállnak.)

  • Én szeretem, de szerintem se a fenti eset a jó példa a szükségességére (sőt). Inkább a liquidform vagy a mockito API-ját mondaná, nekem azok elég szépek.

  • A Criteria API-t nem dícsértem, csak felhoztam példának. :) Mi akkor használjuk amikor dinamikusan kell összeállítani a query-t.

  • pcjuzer: Igen, tudom :) Csak gondoltam, ha már ráterelődött a szó, akkor a napi igét oda is elhintem egy kicsit:) Amúgy a Hibernate használata megérne (legalább) egy külön posztot is. (És kiváncsi lennék mások véleményére is!)

    Amúgy azóta már rájöttem, hogy tényleg elég szerencsétlen volt a példaválasztás, szemléletesebb lett volna, ha például már meglévő frameworkökből hozok fel példát. Pl. JMock és társai ( egy példa: http://www.jmock.org/jmock1-dispatch.html )

  • Viczián István

    Feb 7th, 2010

    Egy alternatív, bár nagyon hasonló megoldás a builder tervezési mintával: készítesz egy RegistrationDataBuilder osztályt ezekkel a metódusokkal, és az állítja össze a végén a RegistrationData objektumot. Ez talán oo-bb, encapsulation-t megtartja, a mindenféle validáció bele tehető a végén a RegistrationData-t visszaadó metódusba, stb.

Leave a Comment


  • RSS JTechLog – Viczián István java blogja


    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693

    Warning: A non-numeric value encountered in /chroot/home/infokuka/infokukac.com/html/wp-includes/SimplePie/Parse/Date.php on line 693
  • RSS Tajti Ákos C és Java blogja

  • RSS QualityOnTime

  • RSS Adaptive PM

  • RSS Menedzsmentor blog

  • Shelfari: Book reviews on your book blog