Skip to content

Commit 0119435

Browse files
authored
Merge pull request #4 from scijava/simplification-revised
Simplification revised
2 parents 3f8fa41 + 42ce11b commit 0119435

File tree

12 files changed

+382
-148
lines changed

12 files changed

+382
-148
lines changed

README.md

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ For example, `FactoryA` should take `FactoryAOptions` and
1010
expose an optional parameter "`int a`" with the same meaning and default values.
1111

1212
To maintain convenience and type-safety, both `FactoryAOptions` and `FactoryBOptions` should expose
13-
a method `a(int)` to set the optional parameter. But `FactoryAOptions::a` should return an `FactoryAOptions`,
14-
and `FactoryBOptions::a` should return an `FactoryBOptions` to allow chaining more parameters of
13+
a method `a(int)` to set the optional parameter. But `FactoryAOptions::a` should return a `FactoryAOptions`,
14+
and `FactoryBOptions::a` should return a `FactoryBOptions` to allow chaining more parameters of
1515
`FactoryAOptions` and `FactoryBOptions` respectively, while retaining the type of the builder.
1616

1717
Using scijava-optional, this can be achieved as follows:
@@ -21,26 +21,26 @@ one exposing methods to set the parameters, one exposing methods to retrieve par
2121

2222
For setting:
2323
```java
24-
interface OptionA<T extends OptionA<T>> extends Options<T> {
24+
interface OptionA<T> extends Options<T> {
2525
default T a(int a) {
26-
return add("a", a);
26+
return setValue("a", a);
2727
}
2828
}
2929
```
3030
where the `a()` method records the parameter value (with key `"a"`) via the
31-
`add()` method of the `Options` super-interface.
31+
`setValue()` method of the `Options` super-interface.
3232

3333
For getting:
3434
```java
3535
interface ValueA extends Values {
3636
...
37-
default int a() {}
38-
return value( "a", 0 );
37+
default int a() {
38+
return getValueOrDefault( "a", 0 );
3939
}
4040
}
4141
```
4242
where the `a()` method returns the parameter value (with key `"a"` and default value `0`)
43-
via the `value()` method of the `Values` super-interface.
43+
via the `getValueOrDefault()` method of the `Values` super-interface.
4444

4545
Finally, the implementation of `FactoryAOptions` derives from `AbstractOptions` and all desired
4646
subsets of options
@@ -49,17 +49,12 @@ public class FactoryAOptions
4949
extends AbstractOptions< FactoryAOptions >
5050
implements OptionA< FactoryAOptions >, ...
5151
{
52-
static class FactoryAValues
52+
public class FactoryAValues
5353
extends AbstractValues
5454
implements ValueA, ...
55-
{
56-
...
57-
public FactoryAValues(FactoryAOptions options) {
58-
super( options );
59-
}
60-
}
55+
{}
6156

62-
public final FactoryAValues values = new FactoryAValues(this);;
57+
public final FactoryAValues values = new FactoryAValues();
6358

6459
// =======================================================================
6560

@@ -76,49 +71,36 @@ public class FactoryAOptions
7671
protected FactoryAOptions copyOrThis() {
7772
return new FactoryAOptions(this);
7873
}
79-
80-
// =======================================================================
81-
82-
// The following is not necessary, but can be overridden like this
83-
// to make it show up more nicely in IDE auto-complete
84-
85-
@Override
86-
public FactoryAOptions a(int a) {
87-
return OptionA.super.a(a);
88-
}
8974
}
9075
```
9176
The parameter values are exposed through inner class `FactoryAValues` that derives from `AbstractValues`
9277
and all desired subsets of option values.
9378

9479
The only thing that has been omitted from the above example is the parts that provide a nice `toString` implementation
95-
for the values. This is be achieved by
80+
for the values. This is be achieved by overriding the `forEach()` methods in the `Values` interfaces and
81+
implementation
9682
```java
9783
interface ValueA extends Values {
98-
default void buildToString(AbstractValues.ValuesToString sb) {
99-
sb.append("a", a());
84+
default void forEach(BiConsumer<String, Object> action) {
85+
action.accept("a", a());
86+
// and so on, for other parameters defined in this Values interface
10087
}
10188

10289
default int a() {
103-
return value("a", 0);
90+
return getValueOrDefault("a", 0);
10491
}
10592
}
10693
```
10794
and
10895
```java
109-
static class FactoryAValues
96+
public class FactoryAValues
11097
extends AbstractValues
11198
implements ValueA, ...
11299
{
113100
@Override
114-
public String toString() {
115-
final ValuesToString sb = new ValuesToString();
116-
ValueA.super.buildToString(sb);
117-
return sb.toString();
118-
}
119-
120-
public FactoryAValues(FactoryAOptions options) {
121-
super(options);
101+
default void forEach(BiConsumer<String, Object> action) {
102+
ValueA.super.forEach( action );
103+
// and so on, for other implemented Values interfaces
122104
}
123105
}
124106
```

src/main/java/org/scijava/optional/AbstractOptions.java

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22

33
import java.util.LinkedHashMap;
44
import java.util.Map;
5+
import java.util.function.BiConsumer;
56

67
public abstract class AbstractOptions< T extends AbstractOptions< T > > implements Options< T >
78
{
89
final LinkedHashMap< String, Object > theOptions = new LinkedHashMap<>();
910

1011
protected AbstractOptions( T that )
1112
{
12-
that.theOptions.forEach( theOptions::put );
13+
theOptions.putAll( that.theOptions );
1314
}
1415

1516
public AbstractOptions()
@@ -27,14 +28,19 @@ protected T append( final T additionalOptions )
2728
return ( T ) this;
2829

2930
T concat = copyOrThis();
30-
additionalOptions.theOptions.forEach( concat.theOptions::put );
31+
additionalOptions.theOptions.forEach( ( k, v ) -> {
32+
// NB remove existing key for ordering for appended options
33+
concat.theOptions.remove( k );
34+
concat.theOptions.put( k, v );
35+
} );
3136
return concat;
3237
}
3338

3439
@Override
35-
public T add( final String key, final Object value )
40+
public T setValue( final String key, final Object value )
3641
{
3742
final T copy = copyOrThis();
43+
// NB remove existing key for ordering for appended options
3844
copy.theOptions.remove( key );
3945
copy.theOptions.put( key, value );
4046
return copy;
@@ -57,4 +63,62 @@ public String toString()
5763
sb.append( "}" );
5864
return sb.toString();
5965
}
66+
67+
protected abstract class AbstractValues implements Values
68+
{
69+
public void forEach( BiConsumer< String, Object > action )
70+
{
71+
theOptions.forEach( action );
72+
}
73+
74+
@Override
75+
public String toString()
76+
{
77+
final ValuesToString sb = new ValuesToString();
78+
forEach( sb );
79+
return sb.toString();
80+
}
81+
82+
@Override
83+
public < T > T getValueOrDefault( final String key, final T defaultValue )
84+
{
85+
@SuppressWarnings( "unchecked" )
86+
final T value = ( T ) theOptions.get( key );
87+
return value == null ? defaultValue : value;
88+
}
89+
}
90+
91+
protected class ValuesToString implements BiConsumer< String, Object >
92+
{
93+
private final StringBuilder sb;
94+
95+
private boolean first;
96+
97+
public ValuesToString()
98+
{
99+
sb = new StringBuilder().append( "{" );
100+
first = true;
101+
}
102+
103+
@Override
104+
public String toString()
105+
{
106+
sb.append( "}" );
107+
return sb.toString();
108+
}
109+
110+
@Override
111+
public void accept( final String key, final Object value )
112+
{
113+
if ( first )
114+
first = false;
115+
else
116+
sb.append( ", " );
117+
sb.append( key );
118+
sb.append( " = " );
119+
sb.append( value );
120+
if ( !theOptions.containsKey( key ) )
121+
sb.append( " [default]" );
122+
}
123+
}
60124
}

src/main/java/org/scijava/optional/AbstractValues.java

Lines changed: 0 additions & 59 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.scijava.optional;
22

3-
public interface Options< T extends Options< T > >
3+
public interface Options< T >
44
{
5-
T add( String key, Object value );
5+
T setValue( String key, Object value );
66
}

src/main/java/org/scijava/optional/Values.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
public interface Values
44
{
5-
< T > T value( String key, T defaultValue );
5+
< T > T getValueOrDefault( String key, T defaultValue );
66
}

0 commit comments

Comments
 (0)