What's the point of DSLs / fluent interfaces

前端 未结 7 1105
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-01 04:11

I was recently watching a webcast about how to create a fluent DSL and I have to admit, I don\'t understand the reasons why one would use such an approach (at least for the give

相关标签:
7条回答
  • 2021-02-01 04:29

    Further to @sam-saffron's suggestion regarding the flexibility of a Fluent Interface when adding a new operation:

    If we needed to add a new operation, such as Pixalize(), then, in the 'method with multiple parameters' scenario, this would require a new parameter to be added to the method signature. This may then require a modification to every invocation of this method throughout the codebase in order to add a value for this new parameter (unless the language in use would allow an optional parameter).

    Hence, one possible benefit of a Fluent Interface is limiting the impact of future change.

    0 讨论(0)
  • 2021-02-01 04:34

    You should read Domain Driven Design by Eric Evans to get some idea why is DSL considered good design choice.

    Book is full of good examples, best practice advices and design patterns. Highly recommended.

    0 讨论(0)
  • 2021-02-01 04:36

    2 - Is this fluent interface approach just a replacement for the non existing named method parameters in C#? Would named parameters make fluent interfaces obsolete, e.g. something similar objective-C offers:

    Well yes and no. The fluent interface gives you a larger amount of flexibility. Something that could not be achieved with named params is:

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

    The FromImage, ToLocation and OutputImageFormat in the fluid interface, smell a bit to me. Instead I would have done something along these lines, which I think is much clearer.

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

    Fluent interfaces have the same problems many programming techniques have, they can be misused, overused or underused. I think that when this technique is used effectively it can create a richer and more concise programming model. Even StringBuilder supports it.

    var sb = new StringBuilder(); 
    sb.AppendLine("Hello")
     .AppendLine("World"); 
    
    0 讨论(0)
  • 2021-02-01 04:37

    It's possible to use a variation on a Fluent interface to enforce certain combinations of optional parameters (e.g. require that at least one parameter from a group is present, and require that if a certain parameter is specified, some other parameter must be omitted). For example, one could provide a functionality similar to Enumerable.Range, but with a syntax like IntRange.From(5).Upto(19) or IntRange.From(5).LessThan(10).Stepby(2) or IntRange(3).Count(19).StepBy(17). Compile-time enforcement of overly-complex parameter requirements may require the definition of an annoying number of intermediate-value structures or classes, but the approach can in some cases prove useful in simpler cases.

    0 讨论(0)
  • 2021-02-01 04:39

    I would say that fluent interfaces are slightly overdone and I would think that you have picked just one such example.

    I find fluent interfaces particularly strong when you are constructing a complex model with it. With model I mean e.g. a complex relationship of instantiated objects. The fluent interface is then a way to guide the developer to correctly construct instances of the semantic model. Such a fluent interface is then an excellent way to separate the mechanics and relationships of a model from the "grammar" that you use to construct the model, essentially shielding details from the end user and reducing the available verbs to maybe just those relevant in a particular scenario.

    Your example seems a bit like overkill.

    I have lately done some fluent interface on top of the SplitterContainer from Windows Forms. Arguably, the semantic model of a hierarchy of controls is somewhat complex to correctly construct. By providing a small fluent API a developer can now declaratively express how his SplitterContainer should work. Usage goes like

    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);
    

    I have now reduced the complex mechanics of the control hierarchy to a couple of verbs that are relevant for the issue at hand.

    Hope this helps

    0 讨论(0)
  • 2021-02-01 04:48

    Consider:

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

    What if you used less clear variable names:

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

    Imagine you've printed this code out. It's harder to infer what these arguments are, as you don't have access to the method signature.

    With the fluent interface, this is clearer:

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

    Also, the order of methods is not important. This is equivalent:

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

    In addition, perhaps you might have defaults for the output image format, and the reduction, so this could become:

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

    This would require overloaded constructors to achieve the same effect.

    0 讨论(0)
提交回复
热议问题