After playing around with Java 8 and Generics for some time, I came across an idea while reading some posts about Apple's new programming language Swift.
Swift has AOP-like methods for properties (willSet
and didSet
) and I thought of creating something similar in Java with the help of the new functional interfaces of Java 8.
/**
* Generic wrapper for a property with the possibility to apply functions before, after and instead of getting/setting the value
*
* @author Thomas Eizinger
* @param <T> The type of the wrapped value
*/
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Property<T> {
private T value;
private BiConsumer<T, T> beforeSet = (u, v) -> {};
private Function<T, T> onSet = (v) -> (v);
private Consumer<T> afterSet = (v) -> {};
private Consumer<T> beforeGet = (v) -> {};
private Function<T, T> onGet = (v) -> (v);
private Consumer<T> afterGet = (v) -> {};
public void set(T value) {
this.beforeSet.accept(this.value, value);
this.value = this.onSet.apply(value);
this.afterSet.accept(this.value);
}
public T get() {
this.beforeGet.accept(this.value);
this.value = this.onGet.apply(this.value);
this.afterGet.accept(this.value);
return this.value;
}
public void beforeSet(BiConsumer<T, T> beforeSet) {
this.beforeSet = beforeSet;
}
public void onSet(Function<T, T> onSet) {
this.onSet = onSet;
}
public void afterSet(Consumer<T> afterSet) {
this.afterSet = afterSet;
}
public void beforeGet(Consumer<T> beforeGet) {
this.beforeGet = beforeGet;
}
public void onGet(Function<T, T> onGet) {
this.onGet = onGet;
}
public void afterGet(Consumer<T> afterGet) {
this.afterGet = afterGet;
}
}
Example usage:
public class Foo {
private Property<Integer> bar;
public Foo() {
bar = new Property<>();
bar.beforeSet((oldValue, newValue) -> System.out.printf("bar will be set from %d to %d.%n", oldValue, newValue));
}
public Integer getBar() {
return bar.get();
}
public void setBar(Integer bar) {
this.bar.set(bar);
}
}
Some usecases I could think of would be:
- Notifying observers
- Constraint checks before setting values
- Converting values (e.g. tolowercase for strings)
What do you think of this? Does this put too much logic into properties?
Edit:
I changed the following things based on the review and published the code on github:
- Added null-checks before adding new delegates.
- New delegates are appended after the existing one.
- Changed
onGet
toConsumer<T>
and removedbeforeGet
andafterGet
. - Changed name to
PropertyDecorator