Fluently.Design().Me: inganniamo l’intellisense :-)
Posted by mauro in Software Mason on Wednesday 20 January 2010 at 7:00 PM
Per la felicità di Raffaeu ;-)
Eravamo rimasti qua:
Il giochetto è più semplice del previsto, avete quasi sempre due attori:
- Un entry point che tipicamente è una classe statica non generica che espone dei metodi generici;
- Una classe che viene istanziata e ritornata dall’entry point;
Una cosa del tipo:
static class MyFluentEntryPoint { public static FluentEngineHaving ( T value ) { return new FluentEngine ( value ); } }
e un engine così definito:
Adesso per semplicità immaginiamo di voler essere in grado di fare 2 operazioni:
Funzionare funziona ma incappate nel solito problema della “coding experience”:
Allora fate un secondo tentativo… fallimentare :-), almeno io ci sono incappato:
e cambiate la firma di Configure():
funzionare funziona… avete risolto un problema e ve ne siete creati altri 2, figo:
Possiamo quindi asserire che non va bene :-) In realtà la soluzione è molto ma molto più semplice e l’abbiamo sotto gli occhi tutte le volte che usiamo una Fluent Interface fatta come si deve: interface… appunto :-)
Desiderata
Definiamo quello di cui abbiamo bisogno:
e modifichiamo l’entry point di conseguenza:
A questo punto non ci resta che fare la cosa più banale di tutte: implementare tutte i contratti sulla stessa classe:
garantendoci questo:
è ovvio che se complichiamo/estendiamo/necessitiamo di dare al developer una experience più corposa le cose si complicano e non di poco, ma il concetto resta sempre lo stesso: una singola classe che implementa contratti diversi, del resto la vostra necessità in questo caso è “semplicemente” ingannare l’intellisense :-)
Non è tutto… stay tuned.
.m
class FluentEngine
class FluentEngine
class ConfiguredFluentEngine
public ConfiguredFluentEngine
interface IConfiguredFluentEngine
static class MyFluentEntryPoint
{
public static IFluentEngine
class FluentEngine
![image_thumb[2] image_thumb[2]](http://milestone.topics.it/UserFiles/Mauro/03b2c6db-e678-48b4-8ea8-931e1686d511.png)
![image_thumb[1] image_thumb[1]](http://milestone.topics.it/UserFiles/Mauro/4c1142bf-f6b7-4837-aaba-62a23096d9cf.png)


#1 da raffaeu Wednesday January 2010 alle 05:22
Che dire, sei il mio mito!
#2 da raffaeu Wednesday January 2010 alle 06:23
Ci ho mangiato 'sopra' la tastiera e devo dire che spesso la soluzione piu' semplice e' anche quella che non vai mai ad immaginare. Certo se dovessi applicare tutto cio' a qualcosa come LinQ, il numero di 'flow' da gestire e il numero di interfacce da scrivere sarebbe mastodontico ma lavorandoci un po' credo di poter ottere una soluzione pulita e riciclabile.
Avendo un' ovveride di WF, con molte piu' futures e una fluent interface, per me e' fondamentale avere un meccanismo di scrittura della mia fluent interface che mi consenta di guidare il dev verso scelte forzate di sintassi.
Ottimo!
#3 da Mauro Servienti Wednesday January 2010 alle 07:42
Mi trovi pienamente d'accordo: se una "Fluent Interface" non è semplice, intuitiva e screvra da possibilità di errori nel suo utilizzo tanto vale non usare una Fluent Interface.
Grazie del feedback :-)
.m