Skip to content

Commit 0b230a5

Browse files
committed
Make ListenableVar<T,L> an interface with static create() methods
1 parent 600f919 commit 0b230a5

File tree

4 files changed

+105
-45
lines changed

4 files changed

+105
-45
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.scijava.listeners;
2+
3+
public interface ChangeListener
4+
{
5+
void valueChanged();
6+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.scijava.listeners;
2+
3+
import java.util.concurrent.atomic.AtomicReference;
4+
import java.util.function.BiConsumer;
5+
import java.util.function.Consumer;
6+
7+
/**
8+
* A variable of type {@code T}. Accessible via {@link #get()} /
9+
* {@link #set(Object)}. Listeners of type {@code L} are notified when the
10+
* variable is changed (or is set, alternatively).
11+
*
12+
* @param <T>
13+
* value type
14+
* @param <L>
15+
* listener type
16+
*
17+
* @author Tobias Pietzsch
18+
*/
19+
public class DefaultListenableVar< T, L > implements ListenableVar< T, L >
20+
{
21+
private final AtomicReference< T > ref;
22+
23+
private final Listeners.List< L > listeners;
24+
25+
private final BiConsumer< L, T > notify;
26+
27+
private final boolean notifyWhenSet;
28+
29+
public DefaultListenableVar( final T value, final Consumer< L > notify )
30+
{
31+
this( value, notify, false );
32+
}
33+
34+
public DefaultListenableVar( final T value, final BiConsumer< L, T > notify )
35+
{
36+
this( value, notify, false );
37+
}
38+
39+
public DefaultListenableVar( final T value, final Consumer< L > notify, final boolean notifyWhenSet )
40+
{
41+
this( value, ( l, t ) -> notify.accept( l ), notifyWhenSet );
42+
}
43+
44+
public DefaultListenableVar( final T value, final BiConsumer< L, T > notify, final boolean notifyWhenSet )
45+
{
46+
this.ref = new AtomicReference<>( value );
47+
this.notify = notify;
48+
this.notifyWhenSet = notifyWhenSet;
49+
this.listeners = new Listeners.SynchronizedList<>();
50+
}
51+
52+
@Override
53+
public void set( final T value )
54+
{
55+
final T previous = this.ref.getAndSet( value );
56+
if ( notifyWhenSet || !previous.equals( value ) )
57+
listeners.list.forEach( l -> notify.accept( l, value ) );
58+
}
59+
60+
@Override
61+
public T get()
62+
{
63+
return ref.get();
64+
}
65+
66+
@Override
67+
public Listeners< L > listeners()
68+
{
69+
return listeners;
70+
}
71+
}
Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.scijava.listeners;
22

3-
import java.util.concurrent.atomic.AtomicReference;
43
import java.util.function.BiConsumer;
54
import java.util.function.Consumer;
65

@@ -9,65 +8,48 @@
98
* {@link #set(Object)}. Listeners of type {@code L} are notified when the
109
* variable is changed (or is set, alternatively).
1110
*
11+
* @param <T>
12+
* value type
13+
* @param <L>
14+
* listener type
15+
*
1216
* @author Tobias Pietzsch
1317
*/
14-
public class ListenableVar< T, L >
18+
public interface ListenableVar< T, L >
1519
{
16-
private final AtomicReference< T > ref;
17-
18-
private final Listeners.List< L > listeners;
19-
20-
private final BiConsumer< L, T > notify;
20+
T get();
2121

22-
private final boolean notifyWhenSet;
23-
24-
public ListenableVar( final T value, final Consumer< L > notify )
25-
{
26-
this( value, notify, false );
27-
}
22+
void set( T value );
2823

29-
public ListenableVar( final T value, final BiConsumer< L, T > notify )
30-
{
31-
this( value, notify, false );
32-
}
33-
34-
public ListenableVar( final T value, final Consumer< L > notify, final boolean notifyWhenSet )
35-
{
36-
this( value, ( l, t ) -> notify.accept( l ), notifyWhenSet );
37-
}
24+
Listeners< L > listeners();
3825

39-
public ListenableVar( final T value, final BiConsumer< L, T > notify, final boolean notifyWhenSet )
26+
public static < T > ListenableVar< T, ChangeListener > create( final T value )
4027
{
41-
this.ref = new AtomicReference<>( value );
42-
this.notify = notify;
43-
this.notifyWhenSet = notifyWhenSet;
44-
this.listeners = new Listeners.SynchronizedList<>();
28+
return new DefaultListenableVar<>( value, ChangeListener::valueChanged );
4529
}
4630

47-
public void set( final T value )
31+
public static < T > ListenableVar< T, ChangeListener > create( final T value, final boolean notifyWhenSet )
4832
{
49-
final T previous = this.ref.getAndSet( value );
50-
if ( notifyWhenSet || !previous.equals( value ) )
51-
listeners.list.forEach( l -> notify.accept( l, value ) );
33+
return new DefaultListenableVar<>( value, ChangeListener::valueChanged, notifyWhenSet );
5234
}
5335

54-
public T get()
36+
public static < T, L > ListenableVar< T, L > create( final T value, final Consumer< L > notify )
5537
{
56-
return ref.get();
38+
return new DefaultListenableVar<>( value, notify );
5739
}
5840

59-
public Listeners< L > listeners()
41+
public static < T, L > ListenableVar< T, L > create( final T value, final BiConsumer< L, T > notify )
6042
{
61-
return listeners;
43+
return new DefaultListenableVar<>( value, notify, false );
6244
}
6345

64-
public static < T > ListenableVar< T, Runnable > simple( final T value )
46+
public static < T, L > ListenableVar< T, L > create( final T value, final Consumer< L > notify, final boolean notifyWhenSet )
6547
{
66-
return new ListenableVar<>( value, Runnable::run );
48+
return new DefaultListenableVar<>( value, notify, notifyWhenSet );
6749
}
6850

69-
public static < T > ListenableVar< T, Runnable > simple( final T value, final boolean notifyWhenSet )
51+
public static < T, L > ListenableVar< T, L > create( final T value, final BiConsumer< L, T > notify, final boolean notifyWhenSet )
7052
{
71-
return new ListenableVar<>( value, Runnable::run, notifyWhenSet );
53+
return new DefaultListenableVar<>( value, notify, notifyWhenSet );
7254
}
7355
}

src/test/java/org/scijava/listeners/ListenableVarTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.concurrent.atomic.AtomicBoolean;
44
import java.util.concurrent.atomic.AtomicLong;
5+
56
import org.junit.Assert;
67
import org.junit.Test;
78

@@ -10,21 +11,21 @@ public class ListenableVarTest
1011
@Test
1112
public void testSet()
1213
{
13-
ListenableVar< Long, Runnable > var = ListenableVar.simple( 0L );
14+
final ListenableVar< Long, ChangeListener > var = ListenableVar.create( 0L );
1415
Assert.assertEquals( ( long ) var.get(), 0L );
1516
var.set( 10L );
1617
Assert.assertEquals( ( long ) var.get(), 10L );
1718
}
1819

19-
interface ChangeListener
20+
interface MyChangeListener
2021
{
2122
void changed();
2223
}
2324

2425
@Test
2526
public void testWithConsumer()
2627
{
27-
ListenableVar< Long, ChangeListener > var = new ListenableVar<>( 0L, ChangeListener::changed );
28+
final ListenableVar< Long, MyChangeListener > var = ListenableVar.create( 0L, MyChangeListener::changed );
2829
final AtomicBoolean notified = new AtomicBoolean( false );
2930
var.listeners().add( () -> notified.set( true ) );
3031
var.set( 10l );
@@ -36,7 +37,7 @@ public void testWithConsumer()
3637
@Test
3738
public void testNoNotificationForUnchangedValue()
3839
{
39-
ListenableVar< Long, ChangeListener > var = new ListenableVar<>( 10L, ChangeListener::changed );
40+
final ListenableVar< Long, MyChangeListener > var = ListenableVar.create( 10L, MyChangeListener::changed );
4041
final AtomicBoolean notified = new AtomicBoolean( false );
4142
var.listeners().add( () -> notified.set( true ) );
4243
var.set( 10L );
@@ -51,7 +52,7 @@ interface ValueListener< T >
5152
@Test
5253
public void testWithBiConsumer()
5354
{
54-
ListenableVar< Long, ValueListener< Long > > var = new ListenableVar<>( 1L, ValueListener::valueChanged );
55+
final ListenableVar< Long, ValueListener< Long > > var = ListenableVar.create( 1L, ValueListener::valueChanged );
5556
final AtomicLong notified = new AtomicLong();
5657
var.listeners().add( notified::set );
5758
var.set( 10L );
@@ -61,7 +62,7 @@ public void testWithBiConsumer()
6162
@Test
6263
public void testWithRunnable()
6364
{
64-
ListenableVar< Long, Runnable > var = ListenableVar.simple( 0L );
65+
final ListenableVar< Long, ChangeListener > var = ListenableVar.create( 0L );
6566
final AtomicBoolean notified = new AtomicBoolean( false );
6667
var.listeners().add( () -> notified.set( true ) );
6768
var.set( 10L );

0 commit comments

Comments
 (0)