具有getter和setter的对象的Fluent Interface(Java)

时间:2015-09-23 13:04:25

标签: java fluent-interface

我阅读并欣赏了来自Lukas Eder的文章http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/,我想为课程创建一个Fluent界面。

该类有四个函数("单词" fill1到fill4),允许设置对象属性和四个函数("单词" get1到get4)获取这些属性,但仅限如果已设置所需的属性:

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

第一张图(状态是黑点)显示了我想要做的事情,但正如你所看到的那样?标记不清楚的部分,因为如果保留在第一个图形中,即使只调用了fill2到fill4中的一个,它也会允许调用get4。

第二个图表会强制调用每个fill2到fill4但是强制执行订单并限制如果我想要更改,例如fill3,我还要重置fill2和fill4。

最后一个图表可以满足我的需求,但它有 13 状态!现在,如果我想我只会在fill2到fill4的组中添加一个属性,那么状态的数量会更多爆炸。

enter image description here

编辑:此外,在考虑了更多之后,我注意到我这样做的方式(见下文),甚至无法实现最后一张图,因为在调用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();

    }

}

1 个答案:

答案 0 :(得分:5)

Java中的Fluent接口API在某种程度上受限于您需要通过其他类型表示每个 API状态的事实。这是Java类型是将一组API约束传递给Java编译器以进行验证的唯一方法的结果。

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

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

  2. 自动生成代码。这是一种更加雄心勃勃的方法,但如果您的 API状态 -combinations“爆炸”,它可以为您节省大量的输入和重构工作。我编写了一个名为Byte Buddy的代码生成库,我知道用户使用该库为流畅的API创建接口。 (不幸的是,我在这个问题上与之联系的两个用户没有开源他们的代码。)如果您更愿意创建Java源代码而不是Java字节代码,那么Java poet可能是您的替代方案我也见过这个用例。

  3. 简化您的API,仅验证最常见的错误,同时检查运行时异常中不常见的错误。这通常是一个可行的解决方案,因为它使API更加平易近人。