Free interface (Java) for an object with getters and setters

I read and enjoyed the article http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/ from Lukas Eder, and I would like to create a Fluent Interface for the class.

The class has four functions ("words" fill1 to fill4) that allow you to set attributes of objects and four functions ("words" get1 to fill4) that receive these attributes, but only if the necessary attributes are set:

First I have to fill in the main settings (fill1). After that, I can either get some of these settings (get1 to get3), which are strings. Or I can fill in additional information (fill2 to fill4). But only after each fill2 to fill4 has been called at least once, can final get4 be called. How to do it?

The first graph (states are black dots) shows what I want to do, but how can you see? marks a part that is not clear, because if it is left as it is in the first column, this will allow calling get4, even if only one of fill2 to fill4 was called.

The second graph will make each fill2 fill4 is called, but reports the order and limits it if I want to change, for example. fill3, I have to reset fill2 and fill4.

The last graph will do what I want, but has 13 states! Now, if I assume that I just add another attribute to the fill2 group to fill4, the number of states will explode even more.

enter image description here

Edit: Also, thinking about it again, I noticed that the way I did it (see below) will not even be able to implement the last schedule, because after fill2 is called, we can be in different states - depending on which what happened before.

What should I do / need to do?

Edit: I implement my fluent interfaces a bit like a facade (if I get the right design template). I mean: I leave the actual class almost untouched - returning it (as in the method chain), but having the corresponding state interfaces as return values โ€‹โ€‹in the method signatures. States are represented by nested interfaces. Example:

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(); } } 
+5
source share
1 answer

The free front-end APIs in Java are somewhat limited by the fact that you need to represent each state of the API with a different type. This is because Java types are the only way to associate a set of API constraints with the Java compiler for validation.

Obviously, this is an unfortunate limitation when creating free APIs. To overcome this limitation, you need to:

  • Implement all the API states manually, for example, using the interface. This might be an acceptable solution if your code is unlikely to change, for example. in a project with a rather limited amount that should not live too long. One support class can then implement all the interfaces that represent each state of the API. As long as users do not use reflection expressions or types, the compiler checks that the methods are called in the legal order.

  • Automatic code generation. This is a more ambitious approach, but it can save a lot of typing and refactoring efforts if your API state combinations โ€œexplodeโ€ as you say. I wrote a code generation library called Byte Buddy , and I know users who use the library to create interfaces for the free API. (Unfortunately, the two users I talked about on this issue did not open source.) If you prefer to create Java source code instead of Java bytecode, then a Java poet may be an alternative for you, which I also saw for this use case.

  • Simplify your API only to check for the most common errors when checking for less common errors with runtime exceptions. This is often an acceptable solution because it makes the API more accessible.

+5
source

Source: https://habr.com/ru/post/1232098/


All Articles