Re: Workaround to overcome the generics limitation causes by Erasure
Have you thought about why you have the S parameter here? I have the
intuition it is unnecessary: it is Subject itself right?
public void update(S subject, A arg);
After the observer receive notification from subject, it may need to
access the properties of the subject, in order to get the detail of
the notification message. Yes! we may pass along the notification
message by using the arg. However, this require us to design another
class, just to carry out the notification message. Please see my
sample code in detail later.
Why don't you just have two observers, each doing its function? You
have a method addObserver(Observer) right?
Most of the situation, a single observer need to respond to multiple
subjects.
For more detailed explanation, please refer to a C++ version
http://www.codeproject.com/cpp/observer_with_templates.asp
Here is my sample code.
GUIToDisplayTimeAndTemperature is a GUI application. It will receive
notification from MyTemperature and MyTime, whenever there is a
temperature change or time change. Once it receive the notification,
it will access the properties of MyTemperature and MyTime, and update
the GUI display accordingly, using those subject's properties.
Please note that the following code won't compile, due to Erasure
/*** MyTemperature.java ***/
public class MyTemperature extends Subject<MyTemperature, String> {
/** Creates a new instance of MyTemperature */
public MyTemperature() {
}
public void run() {
System.out.println("MyTemperature is doing some time consuming
calculation...");
result = 980;
System.out.println("MyTemperature calculation is done. Going
to notify all the observers");
notify(this, "Some Extra Arguement from MyTime");
}
public int getTemperature() {
return result;
}
private int result = 0;
}
/*** MyTime.java ***/
public class MyTime extends Subject<MyTime, String> {
/** Creates a new instance of MyTime */
public MyTime() {
}
public void run() {
System.out.println("MyTime is doing some time consuming
calculation...");
result = 100;
System.out.println("MyTime calculation is done. Going to
notify all the observers");
notify(this, "Some Extra Arguement from MyTime");
}
public int getTime() {
return result;
}
private int result = 0;
}
/*** GUIToDisplayTimeAndTemperature.java ***/
public class GUIToDisplayTimeAndTemperature implements
Observer<MyTemperature, String>, Observer<MyTime, String> {
/** Creates a new instance of Main */
public GUIToDisplayTimeAndTemperature() {
MyTemperature temperature = new MyTemperature();
MyTime time = new MyTime();
temperature.attach(this);
time.attach(this);
temperature.run();
time.run();
}
public void update(MyTemperature temperature, String arg) {
System.out.println("GUI : temperature is now " +
temperature.getTemperature());
System.out.println("GUI : here is the arg from temperature " +
arg);
}
public void update(MyTime time, String arg) {
System.out.println("GUI : time is now " + time.getTime());
System.out.println("GUI : here is the arg from temperature " +
arg);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new GUIToDisplayTimeAndTemperature();
}
}
However, based on the suggestion from Daniel Pitts, we might have a
workaround.
Although it make more sense (and better clean design) to have
GUIToDisplayTimeAndTemperature itself to be the "observer of
temperature" and "observer of time", instead of having an anonymous
class to take that role.
At least suggestion from Daniel Pitts gives something which work :)
Thanks!
public class GUIToDisplayTimeAndTemperature {
// public class GUIToDisplayTimeAndTemperature {
/** Creates a new instance of Main */
public GUIToDisplayTimeAndTemperature() {
MyTemperature temperature = new MyTemperature();
MyTime time = new MyTime();
temperature.attach(getTemperatureObserver());
time.attach(getTimeObserver());
temperature.run();
time.run();
}
public Observer<MyTemperature, String> getTemperatureObserver() {
return new Observer<MyTemperature, String>() {
public void update(MyTemperature temperature, String arg)
{
System.out.println("GUI : temperature is now " +
temperature.getTemperature());
System.out.println("GUI : here is the arg from
temperature " + arg);
}
};
}
public Observer<MyTime, String> getTimeObserver() {
return new Observer<MyTime, String>() {
public void update(MyTime time, String arg) {
System.out.println("GUI : time is now " +
time.getTime());
System.out.println("GUI : here is the arg from
temperature " + arg);
}
};
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
new GUIToDisplayTimeAndTemperature();
}
}