【问题标题】:How to design a Fluent Interface?如何设计一个流畅的界面?
【发布时间】:2014-09-21 13:55:03
【问题描述】:

我一直在尝试为我的一个框架设计一个流畅的界面,但似乎我无法理解其中的一部分。我知道我可以使用接口和类来驱动我想要调用的方法。但是请考虑以下情况。

假设我有一个 Person 类,我希望能够做类似的事情

Person.WithName("Steve").WithAge(18).Save();

同样,我也希望我的 API 的调用者执行类似的操作

Person.WithName("Steve").Save();

or

Person.WithAge(18).Save();

但我不希望用户像这样单独调用保存方法

Person.Save();

现在,如果我想设计这样的 API,我该如何实现呢?如果我从 WithName 和 WithAge 方法返回 Person 类的实例,那么我必须将 Save 方法也放在 Person 类中,这意味着用户可以直接调用它。

【问题讨论】:

标签: c# fluent fluent-interface


【解决方案1】:

正如您所指出的,您可以使用界面来控制可见的内容。使用显式接口实现可以让您在某些情况下隐藏方法并在其他情况下公开它们。它还允许您拥有多个具有相同签名的方法。

在这种情况下,我们有一个私有构造函数,因此只能使用其中一个静态入口点来创建 Person。一旦我们有了名字或年龄,我们就会返回一个人的实例,调用WithNameWithAgeSave是有效的。

public class Person : IPersonBuilder
{
  private string _name;
  private int? _age;

  private Person() { }

  public static IPersonBuilder WithName(string name)
  {
    return ((IPersonBuilder)new Person()).WithName(name);
  }

  public static IPersonBuilder WithAge(int age)
  {
    return ((IPersonBuilder)new Person()).WithAge(age);
  }

  IPersonBuilder IPersonBuilder.WithName(string name)
  {
    _name = name;
    return this;
  }

  IPersonBuilder IPersonBuilder.WithAge(int age)
  {
    _age = age;
    return this;
  }

  public void Save()
  {
    // do save
  }
}

public interface IPersonBuilder
{
  IPersonBuilder WithName(string name);
  IPersonBuilder WithAge(int age);
  void Save();
}

如果Person 是一个具有流利接口之外意义的类——它是某种实体——那么我将创建一个返回PersonBuilder 对象的单个静态入口点并移动所有其余的Person 中流利的担忧。

【讨论】:

  • 是的,是的,是的。正是因为这个原因,显式接口在去年成了我的难题
【解决方案2】:

您可能想要区分创建和属性设置。也许你想要这样的东西:

public interface IPerson
{
    IPerson WithName(string name);
    IPerson WithAge(int age);
}

public class Person : IPerson
{
    //You can also add required parameters here.  That'll 
    //ensure that a person is not saved before his specifications
    //are atleast minimally specified.
    public Person() { }
}

new Person().WithAge(18).WithName("Steven").Save();

或者,如果您只是希望开发人员能够构建一个人,而不鼓励在构建后修改该人。

public interface IPersonBuilder
{
    IPersonBuilder WithName(string name);
    IPersonBuilder WithAge(int age);
    IPerson Save()
}

public interface IPerson
{
    public string Name { get; }
    public int Age { get; }
}

public class PersonBuilder
{
    public PersonBuilder() { }
}

new PersonBuilder().WithAge(18).WithName("Steven").Save();

【讨论】:

  • 感谢您的解决方案。我对你的答案投了赞成票,因为我认为我只能标记一个答案。
猜你喜欢
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多