尝试了解如何创建流畅的界面以及何时使用它们

发布于 2024-11-09 17:36:51 字数 1076 浏览 0 评论 0原文

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

界面:

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(); 

最后,这种情况适合流畅的界面吗?或者更传统的方法会更有意义吗?

How would one create a fluent interface instead of a more tradition approach? Here is a traditional approach:

Interface:

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
}

Usage:

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());

I'd like to be able to say:

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

Lastly, is this situation a good fit for fluent interfaces? Or would a more traditional approach make more sense?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜雨飘雪 2024-11-16 17:36:51

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

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

它使得代码非常可读,但仍然让我有点不安的一件事是返回检查。您必须非常确保不能返回空值,否则下一个“流畅调用”将会失败。

The key to making an interface fluent is to ensure the methods all return instances of the interface itself, or some other object that also implements the interface that can continue the processing.

So in your case each of your IXmlDocumentFactory methods has to return an IXmlDocumentFactory so you can continue to call. The final method, if there is one, returns the type you really want?

It makes for very readable code but one thing that still gives me a bit of the willies is return-checking. You have to make very sure that null's can't be returned or else the next 'fluent call' will fail.

放赐 2024-11-16 17:36:51

在我看来,三件事很重要:

1.) 有一个初始方法,它返回您将要使用的流畅接口

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

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

在您的示例中,由于您只有两种方法,因此它的边界很有用 - 通常您会在流畅的界面中拥有更多方法。或者(我个人更喜欢),您可以在 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();

Three things are important in my mind:

1.) There is an initial method that returns the fluent interface you are going to work with

2.) Each method in the class that implements your fluent interface returns itself so you can continue chaining - these are the real fluent methods.

3.) There is a final method that returns the type that you really want to build.

In your example since you only have two methods, its borderline useful - usually you would have more methods in a fluent interface. Alternatively (which I personally prefer) you can offer both options in your API: A fluent API and a more traditional API (i.e. with optional parameters).

In your case would do something like this:

Edited to respond to comment.

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);
    }
}

Then you can use it like this:

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

var xmlDoc = DocumentFactory<int>.From(42)
                                 .Create();
吃→可爱长大的 2024-11-16 17:36:51

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

有关实现示例,请参考诸如 AutofacMoqFluent NHibernate >

IMO, fluent APIs do have their value. Fluently configuring a component feels more like an English sentence, easily read from start to finish. The intent of a developer is more easily comprehended.

For examples of implementation, please refer to such projects as Autofac, Moq and Fluent NHibernate

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文