【问题标题】:Fluent Interface (Java) for object with getters and setters具有 getter 和 setter 的对象的流利接口 (Java)
【发布时间】:2015-09-23 13:04:25
【问题描述】:

我阅读并喜欢 Lukas Eder 的文章 http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/,我想为一个类创建一个 Fluent 接口。

该类有四个函数(“words”fill1 到 fill4)允许设置对象属性和四个函数(“words”get1 到 get4)获取这些属性,但前提是设置了所需的属性:

首先我必须填写基本设置(fill1)。之后,我可以得到一些字符串设置(get1 到 get3)。或者我可以填写更多信息(fill2 到 fill4)。但只有在 每个 fill2 到 fill4 被调用至少一次 之后,才能调用最终的 get4。我该怎么做?

第一张图(状态是黑点)显示了我想要做什么,但是你可以看到 ?标记不清楚的部分,因为如果在第一个图中保持原样,即使仅调用了 fill2 到 fill4 中的一个,它也允许调用 get4。

第二个图将强制每个 fill2 到 fill4 已被调用,但会强制执行顺序并限制如果我想更改例如fill3,我还要重新设置 fill2 和 fill4。

最后一张图可以做我想做的事,但它有 13 个状态!现在,如果我想我只是在填充 2 到填充 4 的组中再添加一个属性,那么状态的数量会爆炸得更多。

编辑:另外,在考虑了更多之后,我注意到我这样做的方式(见下文)甚至无法实现最后一个图表,因为在 fill2被调用时,我们可能处于不同的状态 - 取决于之前发生的事情。

我能/应该做什么?

编辑:我实现流畅的界面有点像外观(如果我的设计模式正确的话)。我的意思是:我几乎没有改变实际的类——返回这个(如在方法链接中),但是在方法签名中将各自的状态接口作为返回值。状态由嵌套接口表示。示例:

public class MyClass implements MyInterface.Empty, MyInterface.Full {

    String stuff;

    private MyClass(){};

    public static MyInterface.Empty manufactureNewInstance(){
        return new MyClass();
    }

    public MyInterface.Full fillStuff(String stuff){
        this.stuff = stuff;
        return this;
    }

    public String getStuff(){
        return stuff;
    }

}

public interface MyInterface {

    public interface Empty {
        public MyInterface.Full fillStuff();
    }

    public interface Full {
        public String getStuff();
    }

}

public class MyMain {

    pulic static void main(String[] args) {

        // For explaination:
        MyClass.Empty myclassEmpty = MyClass.manufactureNewInstance();
        MyClass.Full myclassFull = myclassEmpty.fillStuff("Hello World 1!");
        String result1 = myclassEmpty.getStuff();

        // As fluent chaining:
        String result2 = MyClass.manufactureNewInstance()
            .fillStuff("Hello World 2!")
            .getStuff();

    }

}

【问题讨论】:

    标签: java fluent-interface


    【解决方案1】:

    Java 中的 Fluent 接口 API 受到您需要用不同类型表示每个 API 状态这一事实的限制。这是因为 Java 类型是向 Java 编译器传达一组 API 约束以进行验证的唯一方法。

    显然,在创建流畅的 API 时这是一个不幸的限制。要克服此限制,您需要:

    1. 通过例如接口手动实现所有 API 状态。如果您的代码不太可能更改,这可能是一个可行的解决方案,例如在一个范围相当有限的项目中,不应该存在太久。然后,单个支持类可以实现代表每个 API 状态的所有接口。只要用户不使用反射或类型转换,编译器就会验证方法是否按合法顺序调用。

    2. 自动生成代码。这是一种更加雄心勃勃的方法,但如果您的 API 状态 组合如您所说的那样“爆炸”,它可以为您节省大量输入和重构工作。我编写了一个名为Byte Buddy 的代码生成库,我知道有用户使用该库为流畅的 API 创建接口。 (不幸的是,我在这件事上接触的两个用户没有开源他们的代码。)如果你想创建 Java 源代码而不是 Java 字节码,那么 Java poet 可能是你的替代方案,我也看到了这个用例。

    3. 简化您的 API 以仅验证最常见的错误,同时在运行时通过异常检查不太常见的错误。这通常是一个可行的解决方案,因为它使 API 更易于使用。

    【讨论】:

    • 非常感谢。这两个代码生成项目看起来很吸引人。然而,为代码生成编写所有这些代码似乎并不比直接编写接口/类更快。我更新了关于立面部分的问题。
    • 代码生成可以帮助您自动解析流畅界面的所有排列。例如,我可以要求你编写一个程序来打印数字 1-5 的所有排列。这将是一个简短的程序,但写下所有数字将花费大量时间。您的流利界面类似。您可以描述代码生成器如何创建所有可能的排列,而无需自己写下来。这通常不太容易出错(尤其是在重构时)并且实施起来更快。
    • 好点。找到我的问题的答案可能会有所帮助,但还没有回答(见编辑)。尽管如此:已经非常感谢了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 2012-10-05
    • 2013-04-09
    • 1970-01-01
    • 2016-12-08
    • 1970-01-01
    相关资源
    最近更新 更多