-
Notifications
You must be signed in to change notification settings - Fork 81
/
Traits.java
124 lines (93 loc) · 2.61 KB
/
Traits.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package dev.nipafx.demo.java10.lang.var;
import java.math.BigDecimal;
public class Traits {
public static void main(String[] args) {
var ecorp = new ECorp();
report(ecorp);
}
/*
* DOWNSIDES
*
* - requires considerable amount of boilerplate
* - has a non-trivial structure
* - delegating interface has less flexibility than a class
* - Object's methods can not be default-implemented,
* so toString, equals, hashCode, ... can never be forwarded
* to existing implementation
*
* ALTERNATIVES
*
* - extension type collecting all needed methods
* - utility methods
*/
public static void report(Megacorp megacorp) {
// without `var` there would be no way to declare a variable
// of type `IsSuccessful` and `IsEvil`
var corp = (MegacorpDelegate & IsSuccessful & IsEvil) () -> megacorp;
System.out.printf(
"Corporation %s is %s and %s.\n",
corp.name(),
// relying on `IsSuccessful`
corp.isSuccessful() ? "successful" : "a failure",
// relying on `IsEvil`
corp.isEvil() ? "evil" : "a failure"
);
}
// important domain concept, used throughout the system
interface Megacorp {
String name();
BigDecimal earnings();
BigDecimal taxes();
}
static class ECorp implements Megacorp {
@Override
public String name() {
return "E-Corp";
}
@Override
public BigDecimal earnings() {
// "One. Million. Dollars"
return new BigDecimal("1000000");
}
@Override
public BigDecimal taxes() {
return BigDecimal.ONE;
}
}
// created right next to `Megacorp` to allow easy extension
// throughout the system
@FunctionalInterface
interface MegacorpDelegate extends Megacorp {
// there can only be this one abstract method
Megacorp delegate();
@Override
default String name() {
return delegate().name();
}
@Override
default BigDecimal earnings() {
return delegate().earnings();
}
@Override
default BigDecimal taxes() {
return delegate().taxes();
}
// because `Object` methods can not have default implementations,
// there can be no delegations for toString, equals, hashCode, ... :(
}
// these are concepts that are only useful in a very narrow part of the system
// and so they are not added to the original interface to prevent polluting it
// with too many methods;
// these traits must not have abstract methods
interface IsSuccessful extends Megacorp {
BigDecimal SUCCESS_BOUNDARY = new BigDecimal("500000000");
default boolean isSuccessful() {
return earnings().compareTo(SUCCESS_BOUNDARY) > 0;
}
}
interface IsEvil extends Megacorp {
default boolean isEvil() {
return true;
}
}
}