在C#3中编写流畅接口的技巧

时间:2008-10-22 07:13:49

标签: c# design-patterns fluent-interface

我正在为C#中的流畅接口提供一些好的技巧。我自己只是在学习它,但是热衷于在我正在阅读的文章之外听到别人的想法。特别是我在追求:

  1. 什么时候说得太流利了?
  2. 有没有流利的模式?
  3. C#中的内容使流畅的界面更流畅(例如扩展方法)
  4. 是一个复杂流畅的界面还是一个流利的界面?
  5. 重构以获得流畅的界面或重构现有的流畅界面
  6. 您曾与之合作或推荐的任何好例子吗?
  7. 如果您可以发布一个提示或思想,或每个帖子的任何内容。我想看看他们如何投票。

    提前谢谢。

8 个答案:

答案 0 :(得分:27)

我作为流畅界面的消费者所经历的最大挑战是,他们中的大多数都不是真正流畅的界面 - 相反,它们实际上是我倾向于称为“易读界面”的实例。

流畅的界面意味着它的主要目标是使其易于发声,而清晰的界面意味着其主要目标是易于阅读。大多数流畅的界面往往难以编写代码,但相反之后其他人也很容易阅读。

Assert().That().This(actual).Is().Equal().To(expected).
    Except().If(x => x.GreaterThan(10));

...比在代码中实际编写更容易阅读!

答案 1 :(得分:18)

关于你的第四点;

是的我认为复杂的流畅界面仍然可以流畅。

我认为流畅的界面有点妥协。 (虽然很好!)关于使用自然语言进行编程的研究很多,而且一般来说,自然语言不够精确,无法表达程序。

Fluent接口的构造使得它们像编程语言一样编写,只允许用自然语言表达的一小部分内容,但它们就像一种自然语言一样。

例如,如果你看一下犀牛嘲笑,那么与普通的图书馆相比,写作部分很复杂。由于流畅的界面,我花了更长的时间来学习,但它使代码更容易阅读。因为程序通常只写一次并且阅读时间不止一次,所以这是一个很好的权衡。

所以要点一点我的观点。一个流畅的界面,编写复杂但易于阅读仍然可以流畅。

答案 2 :(得分:11)

当使用继承和流畅的接口时,你会遇到麻烦,因为使用多态方法会破坏你的调用链,你绝对不希望通过在不需要它们的情况下使用丑陋的强制转换和paranthesis来使你的接口不流畅。 我写了一篇关于模式的文章,它为您提供了使用泛型构建器和泛型约束的泛型扩展方法的解决方法: http://liviutrifoi.wordpress.com/2009/02/16/fluent-interfaces-constraints-at-compile-time/

答案 3 :(得分:8)

Moq隐藏了未发布的方法,例如equals,ToString等,以使其流畅的界面更易于使用。

Hiding System Object是一篇解释这样做的好处的文章。

答案 4 :(得分:7)

在你的第2和第3个问题上;

我注意到了三种流畅的模式

第一个使用using语句(C#2.0)在某个上下文中运行代码,例如:

using(var transaction = new Transaction())
{
  // ..
  // ..
}

这使用Transaction的构造函数和disposer来设置事务,然后在此上下文中运行代码。

第二个几乎一样,但是使用lambda,例如在Rhino Mocks中使用了很多。

(new Transaction()).Run( () => mycode(); );

最着名的流畅接口是使用返回类型来链接方法调用。大多数方法返回此方法,因此您可以在同一对象上链接调用。但您也可以根据调用的方法返回不同的对象来更改上下文。如果你有一个只能在事务中运行的对象(抱歉不能想到另一个例子)你可以给它一个StartTransaction方法,它返回一个初始化的事务,你可以在伪代码中运行call run和stoptransaction: / p>

class Runner
{
  Transaction StartTransaction()
  {
    return new Transaction(this);
  }
}

class Transaction
{
  Transaction Run()
  Transaction StopTransaction()
}

呼叫看起来像

var runner = new Runner();
runner
  .StartTransaction()
  .Run()
  .StopTransaction();

当然你需要添加各种错误处理等。

答案 5 :(得分:7)

我也只是在学习如何为工作中的小应用程序编写流畅的界面。我已经四处询问并进行了一些研究,发现编写流畅界面的好方法是使用“Builder模式”,阅读更多相关信息here

从本质上讲,这就是我开始创作的方式:

public class Coffee
{
    private bool _cream;
    private int _ounces;

    public Coffee Make { get new Coffee(); }

    public Coffee WithCream()
    {
        _cream = true;
        return this;
    }

    public Coffee WithOuncesToServe(int ounces)
    {
        _ounces = ounces;
        return this;
    }
}

这是a similar question的一个交叉帖子,用于在流畅的界面中实现闭包。

答案 6 :(得分:4)

有一点是你必须考虑英语语法的形态,并确保你没有在下面引入未记录的顺序耦合。

// Snarky employees get a raise.
employees.WhereSnarky().GiveRaise();

VS

// Depending on implementation, everyone may get a raise.
employees.GiveRaise().WhereSnarky();

答案 7 :(得分:2)

前段时间我对你现在的怀疑有同样的疑问。我做了一些研究,现在我正在撰写一些帖子来帮助完成这些主题。

在我的博客上查看:

Guidelines to Fluent Interface design in C# part 1

在接下来的帖子中,我将介绍你提到的每一点。

祝你好运 AndréVianna