Vítejte na blog.vyvojar.cz Přihlásit | Registrovat | Pomoc

Vlko napísal ...

.. mostly harmless ...
FluentInterface

Čo to FluentInterface je?

Fluent v preklade znamená  plynulý nuž a FluentInterface je spôsob ako zapísať na prvý pohľad neprehľadnú inicializáciu triedy, prípadne nejake tie operacie do trošku ľudsky čitateľnejšej formy.

Ako to vyzera v súčastnosti?

Veci je najlepšie vidieť na príklade (použitý príklad je z blogu Ayende @ Rahien).

Ulohou je poslať mail pre aktuálne prihlaseného užívateľa z adresy systému s určitými nastaveniami a s hlavičkou a telom správy.

SendMail( 	
new Lookup(EntityName.systemuser, GetAccountOwner().Value),
new Lookup(EntityName.queue, Settings.Default.ControlQueueID),
title,
body,
GetAccountOwner(),
PostState.new_parentpolicy.Value,
PickLists.EmailPriority.Type.High);

Takýto kód ale veľa nikomu nepovie, preto môžme v rámci čitateľnosti napísať niečo taketo:

Owner owner = GetAccountOwner();
Lookup to = new Lookup(EntityName.queue, Settings.Default.ControlQueueID);
Lookup from = new Lookup(EntityName.systemuser, owner.Value);
Guid regarding = PostState.new_parentpolicy.Value;
Picklist priority = PickLists.EmailPriority.Type.High;
SendMail(from, to, title, body, owner, regarding, priority);

Tento spôsob už je prehľadnejší, ale dá sa to vyriešiť aj lepšie?

Použitie FluentInterface

Najskôr začneme najprehľadnejšie ako sa dá a to kódom:

Owner owner = GetAccountOwner();
Email
.Owner(GetAccountOwner())
.From(EntityName.systemuser, owner.Value)
.To(EntityName.queue, Settings.Default.ControlQueueID)
.Regarding(PostState.new_parentpolicy.Value)
.Priority(PickLists.EmailPriority.Type.High)
.Title(title)
.Body(body)
.Send();

 Takýto kód je prehľadný, je jednoducho možné vynechať určitý parameter, pripadne postupnosť zmeniť (samozrejme okrem posledného Send:).

Implementácia FluentInterface

Fluent interface je možné implementovať buď pomocnou triedou, alebo wrapperom nad existujúcou triedou.

Doležité je, aby dana trieda vrátila z každej fluent funkcie sama seba, teda this.

Koho téma zaujala, môže viac informácii získať na nasledujúcich stránkach:

Tak to je všetko, občas mam vždy chuť nakoniec napísať, že rád sa s čitateľom stretnem pri ďalšom článku (tentoraz o vzore Inversion of Control), ale vždy keď sľúbim druhu časť nejakého článku, môžem so stopercentnou istotou povedať, že to zostane vo sfére snov:). Čo by bolo možno škoda, pretože by som rád vytvoril zopár článkov o projektu Castle, kde práve IoC použitý vo kompnente MicroKernel/Windsor by bol určite úvodnou témou takejto série.

 

Posted: Friday, September 28, 2007 1:12 PM by vlko

Komentář

rob napsal:

Nápad je to určitě zajímavý, ale myslím, že by to chtělo i trochu kritiky. Není všechno zlato co se třpytí.

Kde vidím problémy:

a) pracnost - na každou metodu budu psát ještě pomocnou wrapper třídu

b) udržovatelnost - kromě změny metody musím měnit i wrapper

c) ladění - není jednoduše možné si odkrokovat co se to vlastně kam posílá (na tu poslední řádku .Send si breakpoint prostě nedám). Z tohoto pohledu je nelepší to první "zpřehlednění", kdy se parametry předpřipraví do lokálních proměnných, což je ostatně věc, kterou používá snad každý právě tehdy když potřebuje něco odladit v předávaných parametrech.

Na řešení problému a) i b) by asi šlo udělat nějaký generátor, ale ruku na srdce - stojí to za to, když mi to pak bude stěžovat ladění?

Takže můj názor: pěkná akademická (rozuměj v praxi obtížně použitelná) hříčka.

# September 28, 2007 5:41 PM

tomas napsal:

Souhlasim ze je to elegantni ciste objektove reseni, ale v praxi bude asi docela otrava to implementovat.

V C# 3 se da podobne veci dosahnout jednodussim zpusobem pomoci nove syntaxe na inicializaci objektu:

new SendMail() {

 Owner = GetAccountOwner(),

 From = ...

 Regarding = PostState.new_parentpolicy.Value,

 Priority = PickLists.EmailPriority.Type.High,

 Title = title,

 Body = body

}.Send();

Jinak, v F# se daji podobnym zpusobem zapisovat i parametry pro volani metod a je mozne aby argument byl optional, takze podobne problemy lze resit jeste s mensim mnozstvim zbytecne prace (tj. neni ani potreba definovat zbytecnou tridu jako v tomto C# 3 prikladu).

# September 28, 2007 6:13 PM

Jakublog napsal:

Temer stejny zpusob pouzivam u vygenerovane datove vrstvy pro volani ulozenych procedur. Dobre se to pouziva, dobre se to cte, pri refaktoringu neprekazi - ba naopak.

Ale je to spousta kodu "navic", ktery by se mi rucne psat rozhodne nechtelo.

# September 29, 2007 8:08 PM

pbouda napsal:

Za sebe mohu říci, že mi nějak uniká smysl. Chápu (nebo si to alespoň myslím), jak FluentInterface funguje a k čemu je dobrý, ale osobně nevidím v jeho použití přínos, který by ospravedlňoval práci s jeho implementací. Osobně mi ani jeden z "odstrašujících příkladů" nevadí, pouze ten první mi přijde poněkud těžkopádný pro ladění.

Souhlasím s Tomášem, že nové konstrukty z C#3.0 nabízejí způsoby, jak se FluentInterface vyhnout, a přitom dosáhnout podobného efektu.

# October 1, 2007 1:31 PM

Jakublog napsal:

2 pbouda. Pomoci fluent interface lze udelat napriklad takovyto zapis ( v C#3.0 ho nahrazuzuje LINQ ):

Database db = GetCurrentDatabase();

MyTable tbl = new MyTable();

db.Select( tbl.PK, tbl.Name, tbl.Size, tbl.Count, tbl.Price )

   .Where( tbl.Size < 20 )

   .And( tbl.Count > 10 )

   .Or( tbl.Count == 1 )

   .OrderByAsc( tbl.Name )

   .Execute( tbl );

ktery je imho pro vyvoj lepsi nez stringova alternativa

# October 2, 2007 9:20 AM

vlko napsal:

No mozno by sa hodil aj nejaky ten komentar odomna:)

FluentInterface ma urcite svoje pouzitie v casto pouzivanych triedach, kde je nejaka preprocessed cast, ktora moze mat viac krokov (nepovinnych) a chceme to napisat tak, aby bolo vidno, ze tieto kroky na seba nadvadzuju.

Cize nejaky ten kus kodu navyse urcite neobstoji v porovnani s citatelnostou kodu.

Mozno by sa hodil pouzit trosku iny kus kodu, ale tento sa mi zdal najlepsi na popis funkcnosti, treba pozriet odkazujuce linky.

BTW: kde sa taketo nieco pouziva, napr ako pise Jakublog v pripade OR wrapperov, alebo v roznych testing frameworkov (RhinoMock).

# October 2, 2007 11:14 AM
Vytvoření nového komentáře

(povinný) 

(povinný) 

(nepovinný)

(povinný) 

Opiš čísla, která vidíš na obrázku:

Upozornění na nové komentáře

Pokud chčeš dostávat upozornění emailem na změny u toho příspěvku,tak se zaregistruj zde.zde

Odebírat komentáře k tomuto příspěvku pomocí RSS