Making my class 'fluent'

强颜欢笑 提交于 2019-12-25 05:36:17

问题


I discovered yesterday that I can simulate a fluent interface if I return the class instance from each method like this...

public class IsThisFluent
{
    public IsThisFluent Stuff()
    {
        //...
        return this;
    }

    public IsThisFluent OtherStuff()
    {
        // ...
        return this;
    }
}

Is this all there is to it?

I admit, I'm a bear of very little brain and I want to carry on this this but I thought it might be best to check with a grown up.

Am I missing something?

Is there a 'gotcha' that I haven't spotted with this pattern?


回答1:


return this is not all there is to fluent interfaces. Chaining methods is a simplistic form of building a fluent API, but fluent APIs generally look like DSLs (domain specific languages) and are much, much harder to design.

Take Moq as an example:

new Mock<IInterface>()
    .Setup(x => x.Method())
    .CallBack<IInterface>(Console.WriteLine)
    .Returns(someValue);
  • The Setup method, defined on the type Mock<T>, returns an instance of ISetup<T, TResult>.

  • The Callback method, defined for ICallback<TMock, TResult> returns an instance of IReturnsThrows<TMock,TResult>. Note that ISetup<T, TResult> extends IReturnsThrows<TMock,TResult>.

  • Finally, Returns is defined on IReturns<TMock,TResult> and returns IReturnsResult<TMock>. Also note that IReturnsThrows<TMock,TResult> extends IReturnsResult<TMock>.

All these little nuances are there to force you to call these methods in a particular order, and to forbid you from calling Setup twice in a row, for example. Or from calling Returns before you call Setup.

These details are very important to ensure a good user experience.

To read more on designing fluent interfaces, take a look at Martin Fowler's article on FluentInterface. FluentAssertions is another prime example of how complex the design might get - but also of how much more readable the outcome is.




回答2:


That's pretty much it.

Here's a really good article on it: http://rrpblog.azurewebsites.net/?p=33

EDIT
The original site seems to have died, so here's WayBackMachine to the rescue

I also really like this example from this answer: https://stackoverflow.com/a/1795027/131809

public class Coffee
 {
    private bool _cream;

    public Coffee Make { get new Coffee(); }
    public Coffee WithCream()
    {
      _cream = true;
      return this;
    }
    public Coffee WithOuncesToServe(int ounces)
    {
      _ounces = ounces;
      return this;
    }
 }

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);

Which reminds me, I need a coffee now.




回答3:


Nope, that's pretty much it.

The idea behind is that you can chain method calls together manipulating internal state as you go. Ultimately the main goal of a Fluent interface is readability, LINQ being a very good example of one.



来源:https://stackoverflow.com/questions/29694576/making-my-class-fluent

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!