Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
You have 2 free stories left this month. Sign up and get an extra one for free.
Martin Fowler, who coined the term Fluent Interfaces 15 years ago,
famously wrote in his book Refactoring: Improving the Design of Existing
Code:
“Any fool can write code that a computer can Top highlight
All code examples will be in Java, or reference Java frameworks. But the
general principles of fluent interfaces apply to any other language, too.
. . .
Fluent Interfaces
As with many other design patterns, the core concept can be summarized
in a short sentence:
There are three ways in which we can have more fluent code.
1 // CORRECT
2 BigDecimal basePrice = new BigDecimal("9.99");
3 BigDecimal withTaxes = basePrice.multiply(new BigDecimal("1.19"));
4
5 // INVALID
6 BigDecimal basePrice = new BigDecimal("9.99");
7 basePrice.multiply(new BigDecimal("1.19")); // won't modify basePrice
In Java, we can use builders to get around the lack of named parameters.
. . .
1 class Developer {
2 private String email;
3 private String name;
4 private List<String> languages;
5
6 public String getEmail() {
7 return this.email;
8 }
9
10 public void setEmail(String email) {
11 this.email = email;
12 }
13
14 public String getName() {
15 return this.name;
16 }
17
18 public void setName(String name) {
19 this.name = name;
20 }
21
22 public List<String> getLanguages() {
23 return this.languages;
24 }
25
26 public void setLanguages(List<String> languages) {
27 this.languages = languages;
28 }
29 }
A simple POJO, just storing some data, without any extra functionality.
1 class DeveloperBuilder {
2 private String email;
3 private String name;
4
5 private final List<String> languages = new ArrayList<>();
6
7 public DeveloperBuilder email(String email) {
8 if (email == null || email.length() == 0) {
9 throw new IllegalArgumentException("email musn't be null/empty");
10 }
11
12 this.email = email;
13
14 return this;
15 }
16
17 public DeveloperBuilder name(String name) {
18 this.name = name;
19 return this;
20 }
21
22 public DeveloperBuilder language(String lang) {
23 if (lang == null || lang.length() == 0) {
24 throw new IllegalArgumentException("lang musn't be null/empty");
25 }
26
27 if (this.languages.contains(lang)) {
28 return this;
29 }
30
31 this.languages.add(lang);
32
33 return this;
34 }
35
36 public Developer build() {
37 if (email == null || email.length() == 0) {
38 throw new IllegalStateException("email is a required field");
39 }
40
41 if (this.language.isEmpty()) {
42 throw new IllegalStateException("at least one language must be added");
43 }
44
45 Developer developer = new Developer();
46 developer.setEmail(this.email);
47 developer.setName(this.name);
48 developer.setLanguages(this.languages);
49
50 return developer;
51 }
52 }
By using the builder pattern, we still have our simple POJO type, but now
instance creation can also have validation during preparing the builder
and at creating the actual instance.
1 Developer validDev =
2 new DeveloperBuilder().email("ben@example.com")
3 .name("Ben Weidig")
4 .language("Java")
5 .language("Swift")
6 .language("Golang")
7 .build();
8
9 Developer invalidDev1 =
10 new DeveloperBuilder().name("Ben Weidig")
11 .language("Java")
12 .language("Swift")
13 .language("Golang")
14 // throws IllegalStateException
15 .build();
16
17 Developer invalidDev2 =
18 new DeveloperBuilder().email("ben@example.com")
19 .name("Ben Weidig")
20 // throws IllegalArgumentException
21 .language(null)
22 .language("Swift")
23 .language("Golang")
24 .build();
But we can improve our builder, and also the corresponding type, even
more.
The Developer type is now wholly immutable, and can only be created by
using the builder.
1 @Value.Immutable
2 public interface Developer {
3 String getEmail();
4
5 @Nullable
6 String getName();
7
8 @Value.Default
9 default List<String> getLanguages() {
10 return Collections.emptyList();
11 }
12 }
. . .
A lot of code for getting the names of the first five science fiction authors
of 2020 in our collection.
. . .
Conclusion
Fluent interfaces are great for consumption, but not for creation.
We get more control over how we create an object, even split it into
multiple steps. Validation can be integrated at every step. And it helps to
separate the code for creation from the actual representation.
. . .
Resources
FluentInterface (Martin Fowler)
Immutables framework
74 claps
WRIT T EN BY
Greed and climate- How to Conquer Bliss Is Bucolic in 5 things that UX Design
change denial: Pay no Rejection Canada’s New Brunswick should learn from
attention to the man James Malcher Mai Mislang gaming industry
behind the curtain Jerzy Bartoszewicz in
Carl Pope 10Clouds
Mexican X-plainer: Are the ‘Innocent Babies’ How To Survive How T he Media Made
Tacos, Not T lahcos Being Saved Today Quarantine With T he Anthony Scaramucci T he
David Bowles Potentially the Help Of Some Old Jokes Annoying “Moocher”
‘Dangerous Criminals’ of John DeVore in Humungus Ezinne Ukoha
the Future?
Karen Banes in Fearless She
Wrote