E
Eric Sosman
First, I apologize in advance for the length of this
message.
I'm building a model that exports data for display and
manipulation through a separate GUI. When the GUI changes
one of the model's inputs, the model recalculates its outputs
and fires ChangeEvent notifications for any that change;
the GUI registers listeners that tell it when to update its
JTextFields, JRadioButtons, and so on.
The model can also be told to load an entire set of
data en masse from a Reader, so the "input" data items
can also be "outputs" during a load operation, and the GUI
can register listeners on them, too. It turns out that the
only difference between inputs and outputs is whether their
setValue() methods are private to the model or accessible
outside, and whether changing the value sparks recalculation.
"Almost no difference" makes me think "inheritance," so my
design thus far looks like
class Model {
class Value {
private Object value;
private void setValue(Object newValue) {
if (! newValue.equals(value)) {
value = newValue;
fireChangeEvent();
}
}
private void fireChangeEvent() {
// ... notify listeners
}
// ... additional methods and fields
}
class Variable extends Value {
void setValue(Object newValue) {
super.setValue(newValue);
recalculate();
}
}
// data for this model instance
final Variable input1 = new Variable();
final Variable input2 = new Variable();
// ...
final Value output1 = new Value();
final Value output2 = new Value();
// ...
private void recalculate() {
output1.setValue( ... );
output2.setValue( ... );
// ...
}
}
So far, so good. Exporting fields directly, even final
fields, might not be suitable for public classes, but these
are all package-private and fairly tightly associated with
the GUI (although carefully divided from it), so I don't
propose to fret about that set of issues.
But let's look again at that en-masse load operation. If
the loader calls setValue() on each input Variable as it's
encountered, we'll do a whole lot of recalculations and fire
a whole lot of ChangeEvents that we really don't want. After
all, a Model that has some Variables newly-loaded while others
still hold old values may well be in an inconsistent state, and
I'd rather not take the chance of confusing the GUI. So I'd
like to let the loader just "poke" the `value' elements of all
the Variables without going through the setValue() methods
(which would fire ChangeEvents at each call), and just fire a
whole bunch of ChangeEvents after all the loading is finished.
... but this runs into a small snag: The load() method
cannot just do `input1.value = loadedThing' because, as javac
so eloquently puts it, "value has private access in Model.Value".
(There's somewhat of a paradox here, because the `value' fields
of `output1' and `output2' *are* freely accessible within Model;
Value is inside Model, so even its private fields are visible.
Variable is a subclass of Value and might be expected to have a
more "intimate" relation with it than some unrelated sibling
class would, but no: Variable can't see `value' directly, and
code inside Model can't see `value' if it looks at it through
the subclass' distorting lens.)
I've thought of two ways to solve the problem. One is to
up-cast each Variable reference inside the load() method and
write `((Value)input1).value = loadedThing'. The other is to
split the setValue() method into two pieces, one to do the
setting of the new value and the other to fire ChangeEvents as
needed; the load() method would call the "silent setter," which
would be inaccessible from outside Model. I'm not really happy
with either alternative, and wonder (at long last, here's the
question): is there a better way to design this whole thing?
Thanks for your patience, and I look forward to your ideas.
message.
I'm building a model that exports data for display and
manipulation through a separate GUI. When the GUI changes
one of the model's inputs, the model recalculates its outputs
and fires ChangeEvent notifications for any that change;
the GUI registers listeners that tell it when to update its
JTextFields, JRadioButtons, and so on.
The model can also be told to load an entire set of
data en masse from a Reader, so the "input" data items
can also be "outputs" during a load operation, and the GUI
can register listeners on them, too. It turns out that the
only difference between inputs and outputs is whether their
setValue() methods are private to the model or accessible
outside, and whether changing the value sparks recalculation.
"Almost no difference" makes me think "inheritance," so my
design thus far looks like
class Model {
class Value {
private Object value;
private void setValue(Object newValue) {
if (! newValue.equals(value)) {
value = newValue;
fireChangeEvent();
}
}
private void fireChangeEvent() {
// ... notify listeners
}
// ... additional methods and fields
}
class Variable extends Value {
void setValue(Object newValue) {
super.setValue(newValue);
recalculate();
}
}
// data for this model instance
final Variable input1 = new Variable();
final Variable input2 = new Variable();
// ...
final Value output1 = new Value();
final Value output2 = new Value();
// ...
private void recalculate() {
output1.setValue( ... );
output2.setValue( ... );
// ...
}
}
So far, so good. Exporting fields directly, even final
fields, might not be suitable for public classes, but these
are all package-private and fairly tightly associated with
the GUI (although carefully divided from it), so I don't
propose to fret about that set of issues.
But let's look again at that en-masse load operation. If
the loader calls setValue() on each input Variable as it's
encountered, we'll do a whole lot of recalculations and fire
a whole lot of ChangeEvents that we really don't want. After
all, a Model that has some Variables newly-loaded while others
still hold old values may well be in an inconsistent state, and
I'd rather not take the chance of confusing the GUI. So I'd
like to let the loader just "poke" the `value' elements of all
the Variables without going through the setValue() methods
(which would fire ChangeEvents at each call), and just fire a
whole bunch of ChangeEvents after all the loading is finished.
... but this runs into a small snag: The load() method
cannot just do `input1.value = loadedThing' because, as javac
so eloquently puts it, "value has private access in Model.Value".
(There's somewhat of a paradox here, because the `value' fields
of `output1' and `output2' *are* freely accessible within Model;
Value is inside Model, so even its private fields are visible.
Variable is a subclass of Value and might be expected to have a
more "intimate" relation with it than some unrelated sibling
class would, but no: Variable can't see `value' directly, and
code inside Model can't see `value' if it looks at it through
the subclass' distorting lens.)
I've thought of two ways to solve the problem. One is to
up-cast each Variable reference inside the load() method and
write `((Value)input1).value = loadedThing'. The other is to
split the setValue() method into two pieces, one to do the
setting of the new value and the other to fire ChangeEvents as
needed; the load() method would call the "silent setter," which
would be inaccessible from outside Model. I'm not really happy
with either alternative, and wonder (at long last, here's the
question): is there a better way to design this whole thing?
Thanks for your patience, and I look forward to your ideas.