【问题标题】:Trying to understand how to create fluent interfaces, and when to use them试图了解如何创建流畅的界面,以及何时使用它们
【发布时间】:2011-05-26 13:04:51
【问题描述】:

如何创建流畅的界面而不是更传统的方法?这是一种传统的方法:

界面:

interface IXmlDocumentFactory<T>
{
    XmlDocument CreateXml()                    //serializes just the data
    XmlDocument CreateXml(XmlSchema schema)    //serializes data and includes schema
}

interface IXmlSchemaFactory<T>
{
    XmlSchema CreateXmlSchema()                //generates schema dynamically from type
}

用法:

var xmlDocFactory = new XmlDocumentFactory<Foo>(foo);
var xmlDocument = xmlDocFactory.CreateXml();

//or...

var xmlDocFactory = new XmlDocumentFactory<Foo>(foo);
var xmlSchemaFactory = new XmlSchemaFactory<Foo>();
var xmlDocument = xmlDocFactory.CreateXml(xmlSchemaFactory.CreateXmlSchema());

我想说:

var xmlDocument = new XmlDocumentFactory<Foo>(foo).CreateXml().IncludeSchema();
//or...
var xmlDocument = new XmlDocumentFacotry<Foo>(foo).CreateXml(); 

最后,这种情况是否适合流畅的界面?还是更传统的方法更有意义?

【问题讨论】:

    标签: c# .net fluent-interface


    【解决方案1】:

    使接口流畅的关键是确保方法都返回接口本身的实例,或者也实现了可以继续处理的接口的其他对象。

    因此,在您的情况下,您的每个 IXmlDocumentFactory 方法都必须返回一个 IXmlDocumentFactory,以便您可以继续调用。最后一个方法,如果有的话,返回你真正想要的类型?

    它使得代码可读性非常好,但仍然让我有点担心的一件事是返回检查。您必须非常确定不能返回 null,否则下一个“流利的调用”将失败。

    【讨论】:

    • “最后一个方法,如果有的话,返回你真正想要的类型?” 所以最好说:var xmlDocmuent = new XmlDocumentFactory&lt;Foo&gt;(foo).BuildXmlData().IncludeSchema().CreateXml(); 或类似的东西。那是我缺少的部分,因为我查看的所有示例都注意到方法返回 self。
    • @Matt - 我见过几次的事情之一是最终的 '.Build() 方法,其中每个 fluent-method 都在“计划构建”和 . Build() 返回你想要的数据类型。只是一个想法。
    • 我喜欢这样。另外,控制流量呢?如果.SerializeType().AttachSchema().Build() 有效,但.AttachSchema().SerializeType().Build() 无效怎么办?我的意思是,如果 AttachSchema 方法需要首先序列化类型(即,它将模式插入序列化类型)。如果他们在 AttachSchema 和/或 SerializeType 之前调用 Build 会发生什么。
    • @马特。我想这取决于您想要获得的复杂程度。您可以定义实现方法的单独接口,以便在调用返回 AttachSchema 所在接口的 SerializeType 之前调用 AttachSchema 不可用。但是,如果顺序如此复杂,那么 fluent 就是要走的路——也许您需要一个具有不关心顺序的属性或方法的构建器对象,然后 Build 将它们放在一起。
    • 你的第一句话和你最后的回复对我来说很关键。谢谢+1!
    【解决方案2】:

    在我看来三件事很重要:

    1.) 有一个初始方法可以返回您将要使用的流畅界面

    2.) 实现 fluent 接口的类中的每个方法都会返回自身,因此您可以继续链接 - 这些是真正的 fluent 方法

    3.) 有一个 final 方法 可以返回您真正想要构建的类型。

    在您的示例中,由于您只有两种方法,因此它的边界很有用 - 通常您会在流利的界面中拥有更多方法。或者(我个人更喜欢)你可以在你的 API 中提供两个选项:一个流畅的 API 和一个更传统的 API(即带有可选参数)。

    在你的情况下会做这样的事情:

    已编辑以回复评论。

    public interface IXmlDocumentFactory<T>
    {
        XmlDocument Create();                    //serializes just the data
        IXmlDocumentFactory<T> WithSchema(XmlSchema schema);    //serializes data and includes schema
    }
    
    public class DocumentFactory<T> : IXmlDocumentFactory<T>
    {
        private XmlSchema _schema;
        private T _data;
    
        public DocumentFactory(T data)
        {
            _data = data;
        }
        public IXmlDocumentFactory<T> WithSchema(XmlSchema schema)
        {
            _schema = schema;
            return this;
        }
        public XmlDocument Create()
        {
            if (_schema != null)
            {
                //..use schema/data
                return new XmlDocument();
            }
            else //use data
                return new XmlDocument();
        }
    
        public static IXmlDocumentFactory<T> From(T data)
        {
            return new DocumentFactory<T>(data);
        }
    }
    

    那么你可以这样使用它:

    var xmlDoc = DocumentFactory<int>.From(42)
                                     .WithSchema(new XmlSchema())
                                     .Create();
    
    var xmlDoc = DocumentFactory<int>.From(42)
                                     .Create();
    

    【讨论】:

    • 使用这个想法我有:return XmlFactory&lt;Foo&gt;.Build().From(foo).InferSchema().Create();。但是,如果Build().InferSchema().Create() 也可以接受,Build().From(foo).Create() 也可以接受,但Build().InferSchema().From(foo).Create() 不可以呢?我的意思是代码实际上适用于后一种情况,但我不想要它,因为它似乎改变了含义。换句话说,如果他们在调用From() 之前先调用InferSchema(),我希望From() 不是一个选项。
    • @Matt:我有类似的设置 - 只需将 From() 方法设为您的构建器 - 我将添加到我的示例中。
    【解决方案3】:

    IMO,流畅的 API 确实有其价值。流利地配置一个组件感觉更像是一个英文句子,从头到尾都很容易阅读。开发者的意图更容易理解。

    具体实现请参考AutofacMoqFluent NHibernate等项目

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-16
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多