M4N*_*M4N 26 c# dsl fluent-interface api-design
我最近正在观看关于如何创建流畅的DSL的网络直播,我不得不承认,我不明白为什么会使用这种方法(至少对于给定的例子).
网络广播提供了一个图像大小调整类,它允许您指定输入图像,调整大小并使用以下语法将其保存到输出文件(使用C#):
Sizer sizer = new Sizer();
sizer.FromImage(inputImage)
.ToLocation(outputImage)
.ReduceByPercent(50)
.OutputImageFormat(ImageFormat.Jpeg)
.Save();
Run Code Online (Sandbox Code Playgroud)
我不明白这是如何比采用一些参数的"传统"方法更好:
sizer.ResizeImage(inputImage, outputImage, 0.5, ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)
从可用性的角度来看,这似乎更容易使用,因为它清楚地告诉您该方法期望作为输入.相比之下,使用流畅的界面,没有什么可以阻止你省略/忘记参数/方法调用,例如:
sizer.ToLocation(outputImage).Save();
Run Code Online (Sandbox Code Playgroud)
关于我的问题:
1 -是否有某种方法可以提高流畅界面的可用性(即告诉用户他应该做什么)?
2 -这种流畅的界面方法是否只是C#中现有的命名方法参数的替代?命名参数会使流畅的接口过时,例如类似Objective-C提供的东西:
sizer.Resize(from:input, to:output, resizeBy:0.5, ..)
Run Code Online (Sandbox Code Playgroud)
3 -流畅的界面是否过度使用仅仅是因为它们目前很受欢迎?
4 -或者它只是一个被选为网络广播的坏榜样?在这种情况下,请告诉我这种方法的优点是什么,使用它的意义何在.
顺便说一句:我知道jquery,看看它有多容易,所以我不是在寻找关于那个或其他现有例子的评论.
我正在寻找一些(一般)评论来帮助我理解(例如)何时实现流畅的界面(而不是经典的类库),以及实现它时需要注意的事项.
Sam*_*ron 13
2 - 这种流畅的界面方法是否只是C#中现有的命名方法参数的替代?命名参数会使流畅的接口过时,例如类似Objective-C提供的东西:
是的,没有.流畅的界面为您提供了更大的灵活性.使用命名参数无法实现的是:
sizer.FromImage(i)
.ReduceByPercent(x)
.Pixalize()
.ReduceByPercent(x)
.OutputImageFormat(ImageFormat.Jpeg)
.ToLocation(o)
.Save();
Run Code Online (Sandbox Code Playgroud)
流体界面中的FromImage,ToLocation和OutputImageFormat给我一点气味.相反,我会在这些方面做一些事情,我认为这一点更清楚.
new Sizer("bob.jpeg")
.ReduceByPercent(x)
.Pixalize()
.ReduceByPercent(x)
.Save("file.jpeg",ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)
流畅的界面具有许多编程技术所具有的相同问题,它们可能被滥用,过度使用或未充分利用.我认为,当有效地使用这种技术时,它可以创建更丰富,更简洁的编程模型.甚至StringBuilder也支持它.
var sb = new StringBuilder();
sb.AppendLine("Hello")
.AppendLine("World");
Run Code Online (Sandbox Code Playgroud)
我会说流畅的界面有点过头了,我认为你只选了一个这样的例子.
当您使用它构建复杂模型时,我发现流畅的界面特别强大.对于模型,我的意思是例如实例化对象的复杂关系.然后,流畅的接口是引导开发人员正确构造语义模型实例的一种方式.这样一个流畅的界面是将模型的机制和关系与用于构建模型的"语法"分离的绝佳方式,从根本上屏蔽了最终用户的细节,并将可用的动词减少到可能只是那些相关的动词.特殊情况.
你的例子看起来有点像矫枉过正.
我最近在Windows Forms的SplitterContainer上做了一些流畅的界面.可以说,控件层次结构的语义模型在某种程度上很难构建.通过提供一个小的流畅的API,开发人员现在可以声明性地表达他的SplitterContainer应该如何工作.用法就像
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);
Run Code Online (Sandbox Code Playgroud)
我现在已经将控制层次结构的复杂机制简化为几个与手头问题相关的动词.
希望这可以帮助
考虑:
sizer.ResizeImage(inputImage, outputImage, 0.5, ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)
如果使用不太清晰的变量名称会怎样
sizer.ResizeImage(i, o, x, ImageFormat.Jpeg);
Run Code Online (Sandbox Code Playgroud)
想象一下,你已经打印出这个代码了.由于您无法访问方法签名,因此很难推断出这些参数是什么.
通过流畅的界面,这更清晰:
sizer.FromImage(i)
.ToLocation(o)
.ReduceByPercent(x)
.OutputImageFormat(ImageFormat.Jpeg)
.Save();
Run Code Online (Sandbox Code Playgroud)
而且,方法的顺序并不重要.这相当于:
sizer.FromImage(i)
.ReduceByPercent(x)
.OutputImageFormat(ImageFormat.Jpeg)
.ToLocation(o)
.Save();
Run Code Online (Sandbox Code Playgroud)
另外,也许你可能有输出图像格式和缩小的默认值,所以这可能变成:
sizer.FromImage(i)
.ToLocation(o)
.Save();
Run Code Online (Sandbox Code Playgroud)
这将需要重载的构造函数来实现相同的效果.