Language agnostic Fluent接口-方法链接

Language agnostic Fluent接口-方法链接,language-agnostic,design-patterns,oop,fluent-interface,Language Agnostic,Design Patterns,Oop,Fluent Interface,方法链接是我所知道的构建流畅接口的唯一方法 下面是C#中的一个例子: 那么其他人如何创建流畅的界面呢。你是如何创造它的?需要什么语言/平台/技术?在面向对象编程中,通过始终从方法返回包含该方法的相同接口,可以实现流畅的接口。因此,无论版本如何,您都可以使用java、javascript和其他最喜欢的面向对象语言实现这种效果 我发现,通过使用接口,这种技术最容易实现: public interface IFoo { IFoo SetBar(string s); IFoo DoStu

方法链接是我所知道的构建流畅接口的唯一方法

下面是C#中的一个例子:


那么其他人如何创建流畅的界面呢。你是如何创造它的?需要什么语言/平台/技术?

在面向对象编程中,通过始终从方法返回包含该方法的相同接口,可以实现流畅的接口。因此,无论版本如何,您都可以使用java、javascript和其他最喜欢的面向对象语言实现这种效果

我发现,通过使用接口,这种技术最容易实现:

public interface IFoo
{
    IFoo SetBar(string s);
    IFoo DoStuff();
    IFoo SetColor(Color c);
}
这样,实现接口的任何具体类都可以获得fluent方法链接功能。不管好坏我在C#1.1中编写了上述代码


你会发现这种技术在jQueryAPI中随处可见,这就是我构建所谓的fluent接口的方式,或者说是我唯一的尝试

Tokenizer<Bid> tkn = new Tokenizer<Bid>();
tkn.Add(Token.LambdaToken<Bid>("<YourFullName>", b => Util.CurrentUser.FullName))
    .Add(Token.LambdaToken<Bid>("<WalkthroughDate>",
          b => b.WalkThroughDate.ToShortDateString()))
    .Add(Token.LambdaToken<Bid>("<ContactFullName>", b => b.Contact.FullName))
    .Cache("Bid")
    .SetPattern(@"<\w+>");
Tokenizer tkn=新的Tokenizer();
添加(Token.LambdaToken(“,b=>Util.CurrentUser.FullName))
.Add(Token.LambdaToken(“,
b=>b.WalkThroughDate.toSortDateString())
.Add(Token.LambdaToken(“,b=>b.Contact.FullName))
.Cache(“投标”)
.SetPattern(@“);
我的示例需要.NET3.5,但这是我的lambda的唯一原因。正如Brad指出的,您可以在任何版本的.net中执行此操作。虽然我认为lambda有可能带来更有趣的可能性,比如这样

======


其他一些很好的例子是nHibernate的Criteria API,还有一个用于配置nHibernate的fluent nHibernate扩展,但我从未使用过它。AFAIK,术语fluent interface并没有指定特定的技术或框架,而是指设计模式。维基百科确实有广泛的用途

在一个简单的setter方法中,您不会返回
void
,而是
this
。这样,您就可以链接该对象上的所有语句,这些语句的行为与此类似。下面是一个基于原始问题的快速示例:

public class JohnBuilder
{
    private IList<string> languages = new List<string>();
    private IList<string> fluentInterfaces = new List<string>();
    private string butHow = string.Empty;

    public JohnBuilder AddSmartCode(string language)
    {
        this.languages.Add(language);
        return this;
    }

    public JohnBuilder WithFluentInterface(string fluentInterface)
    {
        this.fluentInterfaces.Add(fluentInterface);
        return this;
    }

    public JohnBuilder ButHow(string butHow)
    {
        this.butHow = butHow;
        return this;
    }
}

public static class MyProgram
{
    public static void Main(string[] args)
    {
        JohnBuilder johnBuilder = new JohnBuilder().AddSmartCode("c#").WithFluentInterface("Please").ButHow("Dunno");
    }
}
公共类JohnBuilder
{
私有IList语言=新列表();
私有IList fluentInterfaces=新列表();
私有字符串butHow=string.Empty;
公共JohnBuilder AddSmartCode(字符串语言)
{
this.languages.Add(语言);
归还这个;
}
具有fluentInterface(字符串fluentInterface)的公共JohnBuilder
{
this.fluentInterfaces.Add(fluentInterface);
归还这个;
}
公共JohnBuilder ButHow(字符串ButHow)
{
this.butHow=butHow;
归还这个;
}
}
公共静态类程序
{
公共静态void Main(字符串[]args)
{
JohnBuilder JohnBuilder=new JohnBuilder().AddSmartCode(“c#”)。使用FluentInterface(“请”)。但是如何(“不知道”);
}
}

您可以使用任何版本的.NET或任何其他面向对象语言创建流畅的界面。您所需要做的就是创建一个对象,其方法总是返回对象本身

例如在C#中:

用法:

John = new JohnBuilder()
    .AddSmartCode("c#")
    .WithfluentInterface("Please")
    .ButHow("Dunno");

我想到了在.Net 3.5/C#3.0中可以实现的两件事:

  • 如果对象没有实现流畅的接口,可以使用扩展方法来链接调用

  • 您可能可以使用对象初始化来模拟fluent,但这仅在实例化时有效,并且仅适用于单参数方法(其中属性仅为setter)。这对我来说似乎有点刻薄,但问题就在这里


  • 就我个人而言,如果您正在实现一个构建器对象,我认为使用函数链接没有任何错误。如果生成器对象具有链接方法,则它会保持正在创建的对象干净。只是一个想法

    构建一个流畅的界面背后的核心思想是可读性——阅读代码的人应该能够理解实现了什么,而无需深入研究实现以澄清细节

    在现代OO语言(如C#、VB.NET和Java)中,方法链接是实现这一点的一种方法,但它不是唯一的技术——另外两种是工厂类和命名参数

    还要注意,这些技术并不是相互排斥的——目标是最大限度地提高代码的可读性,而不是方法的纯度

    方法链接

    方法链接背后的关键洞察是永远不要有一个返回void的方法,而是总是返回一些对象,或者更常见的是,返回一些接口,以便进行进一步的调用

    您不必返回调用该方法的同一对象,也就是说,您不必总是“returnthis;”

    一种有用的设计技术是创建一个内部类——我总是在这些类后面加上“表达式”——它公开fluent API,允许配置另一个类

    这有两个优点-它将fluent API保持在一个位置,与类的主要功能隔离,并且(因为它是一个内部类),它可以以其他类无法实现的方式修补主类的内部

    您可能希望使用一系列接口来控制在给定时间点开发人员可以使用哪些方法

    工厂类别

    有时,您需要构建一系列相关的对象,例如NHibernate标准API、Rhino.Mocks期望约束和NUnit 2.4的新语法

    在这两种情况下,您都拥有正在存储的实际对象,但为了使它们更易于创建,工厂类提供了静态方法来制造所需的实例

    例如,在NUnit 2.4中,您可以编写:

    Assert.That( result, Is.EqualTo(4));
    
    “Is”类是一个静态类,其中包含工厂方法,这些工厂方法为NUnit的评估创建约束

    事实上,要考虑到舍入误差和浮点数的其他不精确性,可以为测试指定精度:

    Assert.That( result, Is.EqualTo(4.0).Within(0.01));
    
    (提前道歉-我的语法可能不正确。)

    命名参数Assert.That( result, Is.EqualTo(4));
    Assert.That( result, Is.EqualTo(4.0).Within(0.01));
    
    myDocument.Save("sampleFile.txt", FilePermissions.ReadOnly);
    
    myDocument.Save(file:"SampleFile.txt", permissions:FilePermissions.ReadOnly);
    
    myDocument.Save(toFile:"SampleFile.txt", withPermissions:FilePermissions.ReadOnly);