package org.andork.bind2; import java.util.Collection; import java.util.LinkedList; import java.util.function.Supplier; import org.andork.collect.WeakOrderedCollection; /** * Binder is a source for a value that can change, and it will notify all * {@link Binding}s {{@link #addBinding(Binding) added} to it whenever that * value changes (by calling {@link Binding#update(boolean)}. What the value is * and when it changes depend on the implementations.<br> * <br> * Some {@code Binder}s are {@code Binding}s themselves, and derive their values * from the values of one or more source {@code Binder}s. {@link FunctionBinder} * is an example.<br> * <br> * {@link Binder}s are good for "binding" components of a view to properties of * a model, so that the view is properly updated whenever the model changes. A * typical way to do this is to have a {@link DefaultBinder} in which you set * the model, a {@code Binder/Binding}s bound to that for each property, and * finally {@code Binding}s bound to the property binders that update the view * components with the property binder values. Then if you change the model by * {@linkplain DefaultBinder#set(Object) setting} the model binder's value, it * will automatically perform all the necessary view updates.<br> * <br> * {@link Binder}s are also good for making sure that when one value depends on * many others, you won't forget to update the dependent value when any of the * other values change. Even multiple layers of dependent values can be handled * with ease. The same robustness could be accomplished without {@code Binder}s, * by creating an update method for each value in the chain that calls the * dependent update methods, but such an approach might have more boilerplate * code, and it is less likely that other programmers would remember to preserve * a well-defined system when maintaining/extending it. * * @author andy.edwards * * @param <T> * the value type. */ public abstract class Binder<T> implements Supplier<T> { private Collection<Binding> bindings; private boolean updating; public Binder() { this(new LinkedList<>()); } protected Binder(Collection<Binding> bindings) { this.bindings = bindings; } public final void addBinding(Binding binding) { bindings.add(binding); binding.update(false); } public Binder<T> convertToWeakReferencing() { WeakOrderedCollection<Binding> newBindings = WeakOrderedCollection.newLinkedCollection(); newBindings.addAll(bindings); bindings = newBindings; return this; } @Override public abstract T get(); public final boolean isUpdating() { return updating; } public final void removeBinding(Binding binding) { bindings.remove(binding); binding.update(false); } public final void updateBindings(boolean force) { if (!updating) { updating = true; try { for (Binding binding : bindings) { binding.update(force); } } finally { updating = false; } } } }