event handling a variable change.

M

McGowan

I know that event handling is strictly to monitor a users actions but I
am hoping there is a way to get around it.

I am working a small project containing (at the moment) two beans, the
first bean basically monitors the temperature of a room and the second
bean is supposed to recieve the new data every time the temperature
changes and I am at a total loss as to how to do this.

Is there a way to monitor a variable so that every time it changes an
event listener activates or is there another way around the problem.

Cheers.
 
M

Mike Schilling

McGowan said:
I know that event handling is strictly to monitor a users actions but I
am hoping there is a way to get around it.

I am working a small project containing (at the moment) two beans, the
first bean basically monitors the temperature of a room and the second
bean is supposed to recieve the new data every time the temperature
changes and I am at a total loss as to how to do this.

Is there a way to monitor a variable so that every time it changes an
event listener activates or is there another way around the problem.

This is an excellent reason for having all changes to a variable go through
a setter. It's next to impossible to detect when the value of a field
changes; it's trivial to add behavior to a setter.
 
D

Daniel Pitts

I know this is a long post, please bare with me.


That isn't true. Events can be used in many situations, its very useful
pattern when applied correctly.
am hoping there is a way to get around it.

I am working a small project containing (at the moment) two beans, the
first bean basically monitors the temperature of a room and the second
bean is supposed to recieve the new data every time the temperature
changes and I am at a total loss as to how to do this.
[snip]
This is an excellent reason for having all changes to a variable go through
a setter.
In a way, yes, but in another no. Read below.
It's next to impossible to detect when the value of a field
changes; it's trivial to add behavior to a setter.

In general, public getters and setters can be a bad (read: often
abused) thing. For example, a TemperatureSensor class shouldn't allow
any client to set the temperature, it should handle that on its own.

I read an article [1] which helped me come to that conclusion. Although
the authors views are a *little* extreme, the general principal is
good.

Objects generally should have the following three parts:
* Interface: A way to interact with an object
* Behaviour: The "observable" outcome of interaction.
* Implementation: The hidden cause of the behaviour.

Often times people open up the interface to expose all of the
underlying implementation. Specifically, Java programmers often expose
properties (fields) in the interface that should instead be part of a
hidden state. This is what comes when one blindly follows the
ubiquitous advice that "you should use getters and setters."

The implementation manipulates the state of the object, which should
often be a hidden state. This hidden state is useless to clients of
the object, and may not have the same format from version to version,
or even object to object. The interface should expose what I call
"observable state". In the OP's problem, the observable state would be
the current Temperature.

If you find that some object's state is being manipulated outside of
the defining class, try to find a way to make that manipulation a
method (behaviour) of that object's class instead. Fowler [2] has some
good advice on how to change where behaviour occures.

With those goals in mind, here is how I might define your temperature
monitoring class:

class TemperatureSensor {
private Temperature currentTemp;
final List<TemperatureChangeListener> listeners =
new ArrayList<TemperatureChangeListener>();

public void addTemperatureChangeListener(
TemperatureChangeListener listener) {
listeners.add(listener);
}
/** I'm assuming that the sensor is probably
* going to run in its own thread.
*/

protected void updateTemp() {
Temperature temp = pollTempurature();
if (!temp.equals(currentTemp)) {
setTemp(temp);
}
}
/* Notice that this is *private* for a reason. */
private void setTemp(Temperature temp) {
TemperatureChangeEvent tce =
new TemperatureChangeEvent(this, currentTemp, temp);
currentTemp = temp;
for (TemperatureChangeListener listener: listeners) {
listener.temperatureChanged(tce);
}
}
/**
* Device specific, and should probably
* block the current thread for a little while so that
* it can be called in a loop without taxing the CPU.
*/
protected abstract Temperature pollTemperature();
}


[1] "Why getter and setter methods are evil"

<http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html>

[2] "Refactoring: Improving the Design of Existing Code"

<http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672>
 
M

McGowan

Thanks, the temperature change is not actually going to be monitoring a
real temperature but a temperature range I am going to setup to move
between say 15 degC and 30. I'm pretty sure your post is going to help
me to get this working properly.

Thank you!
 
D

Daniel Pitts

McGowan said:
Thanks, the temperature change is not actually going to be monitoring a
real temperature but a temperature range I am going to setup to move
between say 15 degC and 30.
You could implement the pollTemperature to return the values between 15
and 30.
I'm pretty sure your post is going to help
me to get this working properly.

Thank you!

No problem, glad I could help!

Oh, and a suggestion on encapsulating the Temperature value:

class Temperature {
final double degreesCentigrade;

private Temperature(double degreesCentigrade) {
this.degreesCentigrade = degreesCentigrade;
}

public static Temperature fromCentigrade(double degreesCentigrade)
{
return new Temperature(degreesCentigrade);
}

public double getDegreesCentigrade() {
return degreesCentigrade;
}
}

It may seem like a bit of extra work now, but if you need to handle
scales other than centigrade in the future, this allows you to have all
the conversions in the Temperature class, and existing clients of
Temperature who know how to deal with Centigrade, don't have to change.

You would just need to add a "fromFahrenheit"method which gets a
temperature object by converting to centigrade, and add a
getDegreesFahrenheit" which converts back. Implementation details
hidden, so there is no coupling to the implementation. You could even
decide to store things as Kelvin, or some other format, and no one
would be the wiser.
 
M

Mike Schilling

Daniel Pitts said:
In a way, yes, but in another no. Read below.

In general, public getters and setters can be a bad (read: often
abused) thing. For example, a TemperatureSensor class shouldn't allow
any client to set the temperature, it should handle that on its own.

Yeah, I didn't mean to imply a public setTemperature() method. Your
observation that this method could well be private is well taken.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top