代码之家  ›  专栏  ›  技术社区  ›  M4N

DSL/fluent接口有什么意义

  •  27
  • M4N  · 技术社区  · 15 年前

    我最近在看一个关于 how to create a fluent DSL 我必须承认,我不明白为什么会使用这种方法(至少对于给定的示例)。

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

    我不明白这怎么会比采用一些参数的“传统”方法更好:

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

    sizer.ToLocation(outputImage).Save();
    

    下面是我的问题:

    1 -

    2 -

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

    流畅的界面是否仅仅因为当前流行而被过度使用?

    4 - 或者这只是一个被选为网络广播的坏例子?在这种情况下,请告诉我这种方法的优点是什么,在哪里使用它是有意义的。

    顺便说一句:我知道jquery,并且知道它有多简单,所以我不想找关于它或其他现有示例的评论。

    我更多的是寻找一些(一般性的)注释来帮助我理解(例如)什么时候实现一个流畅的接口(而不是一个经典的类库),以及在实现一个接口时要注意什么。

    7 回复  |  直到 15 年前
        1
  •  13
  •   Sam Saffron James Allen    11 年前

    2-这是流畅的接口方法吗 C#?命名的参数会让你变得流畅吗 过时的接口,例如某物

    是的,不是。流畅的界面给了你更大的灵活性。使用命名参数无法实现的功能有:

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

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

    Fluent接口与许多编程技术存在相同的问题,它们可能被误用、过度使用或未充分使用。我认为,当有效地使用这种技术时,它可以创建一个更丰富、更简洁的编程模型。甚至StringBuilder也支持它。

    var sb = new StringBuilder(); 
    sb.AppendLine("Hello")
     .AppendLine("World"); 
    
        2
  •  9
  •   M4N    15 年前

    我想说,流畅的界面有点过头了,我认为您只选择了一个这样的例子。

    我发现流畅的界面在构建复杂模型时尤其强大。对于模型,我指的是实例化对象的复杂关系。fluent接口是一种引导开发人员正确构建语义模型实例的方法。这样一个流畅的界面是将模型的机制和关系与用于构建模型的“语法”分离开来的一个极好的方法,基本上屏蔽了最终用户的细节,并将可用动词减少到可能与特定场景相关的动词。

    你的例子似乎有点过分了。

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

    希望这有帮助

        3
  •  7
  •   toolkit    15 年前

    考虑:

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

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

    想象一下你已经打印出了这个代码。很难推断这些参数是什么,因为您没有访问方法签名的权限。

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

    此外,方法的顺序也不重要。这相当于:

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

    此外,您可能有输出图像格式的默认值和缩减,因此这可能成为:

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

        4
  •  2
  •   Robert P    15 年前

    如果你在做LINQ,一遍又一遍地操纵一个对象,这是有意义的。

    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?
    

    如果obj2是原始对象的75%,那么这意味着您每次都要制作对象的完整副本(在许多情况下有它的优点,例如,如果您尝试制作同一对象的两个实例,但略有不同)。

    不是所有的类都是这样工作的,做这种设计也没有意义。例如,这种设计风格在硬件驱动程序或GUI应用程序核心的设计中几乎没有用处。只要设计只涉及操作一些数据,这种模式就不错。

        5
  •  2
  •   zendar    15 年前

    Domain Driven Design

    这本书充满了好的例子、最佳实践建议和设计模式。强烈推荐。

        6
  •  1
  •   supercat    13 年前

    可以在Fluent界面上使用变体来强制执行可选参数的某些组合(例如,要求至少存在一个组中的一个参数,并且要求如果指定了某个参数,则必须省略某些其他参数)。例如,可以提供类似于Enumerable.Range的功能,但语法类似于IntRange.From(5).Upto(19)或IntRange.From(5).LessThan(10).steppy(2)或IntRange(3).Count(19).steppy(17)。过度复杂的参数要求的编译时强制可能需要定义大量恼人的中间值结构或类,但在某些情况下,这种方法在更简单的情况下可能会很有用。

        7
  •  0
  •   Community Nick Bolton    7 年前

    进一步 @sam-saffron

    因此,流畅界面的一个可能好处是限制未来变化的影响。