Question

Je regardais récemment une webdiffusion sur le comment créer un DSL fluide et je d'admettre, je ne comprends pas les raisons pour lesquelles on pourrait utiliser une telle approche (au moins pour l'exemple donné).

La webdiffusion a présenté une classe de redimensionnement d'image, qui vous permet de spécifier une entrée image, redimensionnez et enregistrez un fichier de sortie en utilisant la syntaxe suivante (en utilisant C #):

Sizer sizer = new Sizer();
sizer.FromImage(inputImage)
     .ToLocation(outputImage)
     .ReduceByPercent(50)
     .OutputImageFormat(ImageFormat.Jpeg)
     .Save();

Je ne comprends pas comment cela est mieux qu'une méthode « classique » qui prend des paramètres:

sizer.ResizeImage(inputImage, outputImage, 0.5, ImageFormat.Jpeg);

D'un point de vue de la facilité d'utilisation, cela semble beaucoup plus facile à utiliser, car il vous indique clairement ce que la méthode prend en entrée. En revanche, avec l'interface fluide, rien ne vous empêche de ne pas utiliser / oublier un paramètre / méthode d'appel, par exemple:

sizer.ToLocation(outputImage).Save();

Alors à mes questions:

1 - Est-il possible d'améliorer la facilité d'utilisation d'une interface fluide (c.-à-dire à l'utilisateur ce qu'il est censé faire)

?

2 - Cette approche est d'interface fluide juste pour remplacer les paramètres de la méthode nommés non existants en C #? Est-ce que les paramètres nommés rendre les interfaces couramment obsolètes, par exemple quelque chose offres Objective-C similaires:

sizer.Resize(from:input, to:output, resizeBy:0.5, ..)

3 - sont des interfaces couramment surutilisés simplement parce qu'ils sont actuellement populaires

4 - Ou était-ce juste un mauvais exemple qui a été choisi pour la diffusion sur le Web? Dans ce cas, dites-moi quels sont les avantages d'une telle approche sont, où est-il logique de l'utiliser.

BTW. Je sais jquery, et voir comment il est facile rend les choses, donc je ne cherche pas des commentaires à ce sujet ou d'autres exemples existants

Je suis plus à la recherche de certains commentaires (général) pour me aider à comprendre (par exemple) lorsque la mise en œuvre d'une interface fluide (au lieu d'une classe bibliothèque classique), et ce qu'il faut surveiller lors de la mise en œuvre d'un.

Était-ce utile?

La solution

  

2 - Est-ce l'approche d'interface fluide   juste un remplacement pour le non   les paramètres existants de méthode nommée dans   C #? Est-ce que les paramètres nommés faire couramment   interfaces obsolètes, par exemple, quelque chose   similaire objectif-C offre:

Eh bien oui et non. L'interface fluide, vous donne une plus grande quantité de flexibilité. Quelque chose qui ne pouvait pas être réalisé avec params est nommé:

sizer.FromImage(i)
 .ReduceByPercent(x)
 .Pixalize()
 .ReduceByPercent(x)
 .OutputImageFormat(ImageFormat.Jpeg)
 .ToLocation(o)
 .Save();

Le FromImage, ToLocation et OutputImageFormat dans l'interface fluide, odeur un peu pour moi. Au lieu de cela, je l'aurais fait quelque chose dans ce sens que je pense est beaucoup plus claire.

 new Sizer("bob.jpeg") 
 .ReduceByPercent(x)
 .Pixalize()
 .ReduceByPercent(x)
 .Save("file.jpeg",ImageFormat.Jpeg);

interfaces Fluent ont les mêmes problèmes de nombreuses techniques de programmation ont, elles peuvent être utilisées à mauvais escient, surexploitées ou sous-utilisés. Je pense que lorsque cette technique est utilisée, elle peut effectivement créer un modèle de programmation plus riche et plus concis. Même StringBuilder soutient.

var sb = new StringBuilder(); 
sb.AppendLine("Hello")
 .AppendLine("World"); 

Autres conseils

Je dirais que les interfaces sont couramment un peu surfait et je pense que vous avez choisi un seul exemple.

Je trouve les interfaces couramment particulièrement forte lorsque vous construisez un modèle complexe avec elle. Avec le modèle que je veux dire par exemple une relation complexe d'objets instanciés. L'interface fluide est alors un moyen de guider le développeur de construire correctement les instances du modèle sémantique. Une telle interface fluide est alors un excellent moyen de séparer les mécanismes et les relations d'un modèle de la « grammaire » que vous utilisez pour construire le modèle, le blindage essentiellement les détails de l'utilisateur final et de réduire les verbes disponibles à peut-être juste ceux qui sont pertinents dans un scénario particulier.

Votre exemple semble un peu exagéré.

Je l'ai récemment fait une interface fluide au-dessus du SplitterContainer de Windows Forms. On peut dire que, le modèle sémantique d'une hiérarchie des contrôles est quelque peu complexe à construire correctement. En fournissant une petite API couramment un développeur peut maintenant exprimer déclarative comment son SplitterContainer devrait fonctionner. Utilisation va comme

var s = new SplitBoxSetup();
s.AddVerticalSplit()
 .PanelOne().PlaceControl(()=> new Label())
 .PanelTwo()
 .AddHorizontalSplit()
 .PanelOne().PlaceControl(()=> new Label())
 .PanelTwo().PlaceControl(()=> new Panel());
form.Controls.Add(s.TopControl);

Je l'ai maintenant réduit la mécanique complexe de la hiérarchie de contrôle à deux verbes qui sont pertinents pour la question à la main.

Hope this helps

Considérez:

sizer.ResizeImage(inputImage, outputImage, 0.5, ImageFormat.Jpeg);

Que faire si vous avez utilisé les noms de variables moins claires:

sizer.ResizeImage(i, o, x, ImageFormat.Jpeg);

Imaginez que vous avez Printed ce code. Il est plus difficile de déduire ce que ces arguments sont, comme vous n'avez pas accès à la signature de la méthode.

Avec l'interface fluide, cela est plus clair:

 sizer.FromImage(i)
 .ToLocation(o)
 .ReduceByPercent(x)
 .OutputImageFormat(ImageFormat.Jpeg)
 .Save();

En outre, l'ordre des méthodes est sans importance. Ceci est équivalent:

 sizer.FromImage(i)
 .ReduceByPercent(x)
 .OutputImageFormat(ImageFormat.Jpeg)
 .ToLocation(o)
 .Save();

De plus, peut-être que vous pourriez avoir par défaut pour le format d'image de sortie, et la réduction, donc cela pourrait être:

 sizer.FromImage(i)
 .ToLocation(o)
 .Save();

Cela nécessiterait des constructeurs surchargée pour obtenir le même effet.

Il est une façon de mettre en œuvre les choses.

Pour les objets qui ne font que manipuler le même article, encore et encore, il n'y a rien vraiment mal avec elle. Considérez Streams C ++: ils sont le nec plus ultra dans cette interface. Chaque opération retourne à nouveau le flux, vous pouvez donc enchaîner une autre opération de flux.

Si vous faites LINQ, et de faire la manipulation d'un objet à plusieurs reprises, cela fait un certain sens.

Cependant, dans votre conception, vous devez être prudent. Que doit faire le comportement est si vous voulez écarter à mi-chemin? (IE,

var obj1 = object.Shrink(0.50); // obj1 is now 50% of obj2
var obj2 = object.Shrink(0.75); // is ojb2 now 75% of ojb1 or is it 75% of the original?

Si obj2 était de 75% de l'objet original, alors cela signifie que vous faites une copie complète de l'objet à chaque fois (et a ses avantages dans de nombreux cas, comme si vous essayez de faire deux instances du même chose, mais légèrement différente).

Si les méthodes de manipuler simplement l'objet d'origine, alors ce genre de syntaxe est un peu de mauvaise foi. Ce sont des manipulations sur l'objet de manipulations au lieu de créer un objet modifié.

Toutes les classes fonctionnent comme ça, ni est-il logique de faire ce genre de conception. Par exemple, ce style de conception aurait peu ou pas d'utilité dans la conception d'un pilote matériel ou le noyau d'une application graphique. Tant que la conception implique rien que la manipulation des données, ce modèle n'est pas une mauvaise.

Vous devriez lire Domain Driven Design par Eric Evans pour avoir une idée pourquoi DSL considérée comme une bonne conception choix.

livre est plein de bons exemples, meilleurs conseils pratiques et modèles de conception. Hautement recommandé.

Il est possible d'utiliser une variation sur une interface fluide pour appliquer certaines combinaisons de paramètres facultatifs (par exemple, exigent au moins un paramètre d'un groupe est présent, et exigent que si un certain paramètre est spécifié, un autre paramètre doit être omis ). Par exemple, on pourrait fournir une fonctionnalité similaire à Enumerable.Range, mais avec une syntaxe comme IntRange.From (5) .Upto (19) ou IntRange.From (5) .LessThan (10) .Stepby (2) ou IntRange ( 3) .Count (19) .StepBy (17). Compilation application des exigences de paramètres trop complexes peuvent nécessiter la définition d'un nombre gênant de structures à valeur intermédiaire ou des classes, mais l'approche peut dans certains cas se révéler utile dans les cas simples.

De plus @ sam-safran suggestion en ce qui concerne la flexibilité d'une interface Fluent lors de l'ajout d'une nouvelle opération:

Si nous avions besoin d'ajouter une nouvelle opération, comme Pixalize (), puis, dans la «méthode avec plusieurs paramètres de scénario, cela nécessiterait un nouveau paramètre à ajouter à la signature de la méthode. Cela peut alors exiger une modification à chaque invocation de cette méthode tout au long de la base de code afin d'ajouter une valeur pour ce nouveau paramètre (à moins que la langue utilisée permettrait un paramètre optionnel).

Par conséquent, un avantage possible d'une interface Fluent est de limiter l'impact du changement futur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top