My question is about the use of the getManager() method in the OKButtonListener:
This method is called by concrete subclasses in order to get their LaunchManager, as follows:
The purpose of doing this is to get information about the particular launch configuration in order to store the settings in a properties files - i.e. there will be different settings to store for "stand alone mode" and "network mode".
Is this an ideal solution, where you are returning an interface where you will always have to cast it to the concrete type in order to carry out the action you require to carry out?
Is there a way of refactoring this to avoid the need to cast the return type?
Lastly to Roberto, if he is out there - did you use this solution with casting in your actual assignment that you submitted?
When you develop new code (using jdk 1.5 or above) you have some alternatives to avoid this cast:
Hope it helps!
Well champ, in the case that you mentioned, if everything is coded as mentioned in the paper, it will alwyas be safe to cast to StandaloneLaunchManager because that is certainly the object's dynamic type (the static type is LaunchManager).
I wrote this paper after a lot of time spent here, always thinking about a better way to design the assignment and code the project. So, in my solution, for each button, I had a class that implemented ActionListener directly. But it is certainly an effective way to do things, why not? But maybe we could think about a solution with generics in order to avoid the casting. I'll try to do that in the next days.
If I am reading the intention of Roberto's design correctly, then actionPerformed method of the OKButtonListener is operating as a Template Method where the operation to save the properties is delegated off the to particular class that implements OKButtonListener. The implication being that the subclass knows best how to save the properties associated with its LaunchManager.
Based on this logic it seems quite simple to me. Since the subclass of OKButtonListener needs to know about the properties associated with its LaunchManager, then it should have a handle to its LaunchManager. Storing it as a member variable provides the subclass with this handle.
How does this sound?
So, the only difference is that, instead of sending the LaunchManager object to the super class, you are keeping it in the subclass. Well, when I created this code, I thought about sending it to the super class because, since the actionPerformed method is a template method and it is in the super class, you get the Services instance, call LaunchManager's closeWindow() method, then instantiate the MainWindow object, passing the Services instance. So the LaunchManager object has to stay in the super class. Another possible way is to still send the LaunchManager object to the super class and keep a local reference to it, which would be a mix of what you and I did. But I still think that a solution with generics would be more fancy so I'll think about something in the next days.
Roberto Perillo wrote:So the LaunchManager object has to stay in the super class.
But what if you did as I suggested in the code comment and made the getManager method abstract in the super class? Then this would just be another Template Method like the saveProperties method and your actionPerformed method in the super class would still function. Does that sound correct?
Roberto Perillo wrote:Another possible way is to still send the LaunchManager object to the super class and keep a local reference to it, which would be a mix of what you and I did.
Yep, that is what I did initially. But I thought it looked a bit odd so I removed the reference from the super class. If the super class needs access to the LaunchManager I think I would go with an abstract method in the super class.
Roberto Perillo wrote:But I still think that a solution with generics would be more fancy so I'll think about something in the next days.
This would be interesting. On the face of it, I can't see how generics will let you store the reference in the super class as the base type and still allow subclasses to access the concrete subtype.
This approach makes more sense to me, because all your logic with regard to a LaunchManager is in 1 class (hierarchy) and not in a few classes (the StandaloneOKButtonListener contains also some logic to save the properties of the StandaloneLaunchManager). And you need fewer classes, which mean fewer classes to maintain
But this was just my initial thought when I looked at the code mentioned in the OP. Maybe it's mentioned in the text you opted for this approach for some reasons I don't know, because I didn't have read the text (if the design is good, it's self-explanatory and no additional comments are needed).
just my 2 cents.
@Sean: I'll try to think about something in the next days regarding generics... but, if everything is coded as mentioned in the paper, it will always be safe to cast to the dynamic type that corresponds to the way the application was started. At a first glance, keeping the business object in the sub class has the same effect. Only the getManager() method in the OKButtonListener class would have to be abstract and should be implemented in each sub class.
The idea of the these interfaces that extend LaunchManager is to only provide access to the text fields where the user provides data, and they are more likely to be implemented by classes that extend JFrame, or that are the windows so to speak, and thus, they are view components. Although it looks simpler, I don't think they are the right place to instantiate the Data and business objects and to save the properties provided by the user. These tasks are supposed to be performed in Controllers, which are the ActionListeners. So, in my opinion, it is still better to keep separate ActionListener objects, one for each mode.
From that point of view I totally agree with you.
In the end I would not use generics, but opt for the covariant return. It adds no complexity to your classes and you have the cast just in 1 place. You can simply use the getManager()-method without having to cast. It's my preferred solution.
Roberto Perillo wrote:The idea of the these interfaces that extend LaunchManager is to only provide access to the text fields where the user provides data [...].
If this is the only reason, I would suggest another approach. One could make the configuration accessible through a generic method in the LaunchManager:
Each LaunchManager implementation knows which Parameters he is able to provide and each OKButtonListener and the ServerOKButtonListener know which Parameters to request.
By doing so you trade off the compile-time safety of your approach (which is somehow undercut due to the cast) against a less complex design: You can get rid of the interfaces StandaloneLaunchManager, ClientLaunchManager, and ServerLaunchManager.
Both designs have their pros and cons.