Design question re common code

R

Rhino

I need a bit of help in improving the design of some of my common code.

Let's say I have a number of preference dialogs, e.g. FooPreferences,
BarPreferences, and BazPreferences. Each of them is a final class that
extends JDialog and each of them uses a component called ImageChooserPanel,
which extends JPanel.

ImageChooserPanel creates a JPanel that shows an image (JPEG, GIF, etc.) and
provides a button so that the user can invoke a chooser so that a different
image can be selected; the new image is then passed back to the preferences
dialog that is showing the ImageChooserPanel so that it can be used in Foo,
Bar, and Baz, the classes that respectively call FooPreferences,
BarPreferences, and BazPreferences.

Now, I want ImageChooserPanel to get some of the information it needs from
the instance of whichever preferences dialog invoked it. For instance, each
preferences dialog will have Logger and Locale instances that it obtained
from Foo, Bar, or Baz and I would like ImageChooserPanel to get this
information from the preferences dialog so that it knows which Logger and
Locale to use.

I realize that I could pass the Logger and Locale as explicit parameters to
the ImageChooserPanel constructor; that is what I am doing now.

What if I want to get the information a different way, from the instance of
the preferences dialog itself? I know I could pass a reference to the
instance directly to ImageChooserPanel, e.g.:

ImageChooserPanel imageChooser = new ImageChooserPanel(this);

where the above code was invoked in FooPreferences, BarPreferences, and
BazPreferences. Assuming that each of those classes had getters to obtain
their Locale and Logger instances, I'd be all set; all I'd need to do was
create three constructors for ImageChooserPanel and then interrogate the
references to the parent component within each constructor, like this:

public ImageChooserPanel(FooPreferences fooPreferences) {

this.Locale = fooPreferences.getLocale();
this.Logger = fooPreferences.getLogger();
}

public ImageChooserPanel(BarPreferences barPreferences) {

this.Locale = barPreferences.getLocale();
this.Logger = barPreferences.getLogger();
}

public ImageChooserPanel(BazPreferences BazPreferences) {

this.Locale = bazPreferences.getLocale();
this.Logger = bazPreferences.getLogger();
}

But what if I had DOZENS of preference dialogs, not just FooPreferences,
BarPreferences, and BazPreferences? How could I generalize the code so that
there was only a single ImageChooserPanel constructor that could invoke the
appropriate getters of the incoming instance regardless of its class?

I'd prefer NOT to have a big 'if' in this single constructor that tried to
determine the class of the incoming reference if at all possible....

I'm guessing that there is a simple and concise way to access the getters
for the specific instance that is being passed to the ImageChooserPanel
constructor but I can't think of it....
 
T

Tim Terry

Rhino said:
I need a bit of help in improving the design of some of my common code.

Let's say I have a number of preference dialogs, e.g. FooPreferences,
BarPreferences, and BazPreferences. Each of them is a final class that
extends JDialog and each of them uses a component called ImageChooserPanel,
which extends JPanel.

ImageChooserPanel creates a JPanel that shows an image (JPEG, GIF, etc.) and
provides a button so that the user can invoke a chooser so that a different
image can be selected; the new image is then passed back to the preferences
dialog that is showing the ImageChooserPanel so that it can be used in Foo,
Bar, and Baz, the classes that respectively call FooPreferences,
BarPreferences, and BazPreferences.

Now, I want ImageChooserPanel to get some of the information it needs from
the instance of whichever preferences dialog invoked it. For instance, each
preferences dialog will have Logger and Locale instances that it obtained
from Foo, Bar, or Baz and I would like ImageChooserPanel to get this
information from the preferences dialog so that it knows which Logger and
Locale to use.

I realize that I could pass the Logger and Locale as explicit parameters to
the ImageChooserPanel constructor; that is what I am doing now.

What if I want to get the information a different way, from the instance of
the preferences dialog itself? I know I could pass a reference to the
instance directly to ImageChooserPanel, e.g.:

ImageChooserPanel imageChooser = new ImageChooserPanel(this);

where the above code was invoked in FooPreferences, BarPreferences, and
BazPreferences. Assuming that each of those classes had getters to obtain
their Locale and Logger instances, I'd be all set; all I'd need to do was
create three constructors for ImageChooserPanel and then interrogate the
references to the parent component within each constructor, like this:

public ImageChooserPanel(FooPreferences fooPreferences) {

this.Locale = fooPreferences.getLocale();
this.Logger = fooPreferences.getLogger();
}

public ImageChooserPanel(BarPreferences barPreferences) {

this.Locale = barPreferences.getLocale();
this.Logger = barPreferences.getLogger();
}

public ImageChooserPanel(BazPreferences BazPreferences) {

this.Locale = bazPreferences.getLocale();
this.Logger = bazPreferences.getLogger();
}

But what if I had DOZENS of preference dialogs, not just FooPreferences,
BarPreferences, and BazPreferences? How could I generalize the code so that
there was only a single ImageChooserPanel constructor that could invoke the
appropriate getters of the incoming instance regardless of its class?

I'd prefer NOT to have a big 'if' in this single constructor that tried to
determine the class of the incoming reference if at all possible....

I'm guessing that there is a simple and concise way to access the getters
for the specific instance that is being passed to the ImageChooserPanel
constructor but I can't think of it....
why don't you create either a preferences interface which has
getLocale() and getLogger() methods which each specific preferences
dialog can implement. Or create a preferences super class which extends
jdialog then your specialized preferences dialogs can extend the
preferences super class. The second case may be benifical as you may be
writing similar code in each of your foo, bar, and baz preferences
classes that could be moved to the super class. Then you can create a
ImageChooserPanel with a constructor that takes the interface as an
argument or the super class.

Tim
 
R

Rhino

Tim Terry said:
why don't you create either a preferences interface which has
getLocale() and getLogger() methods which each specific preferences
dialog can implement. Or create a preferences super class which extends
jdialog then your specialized preferences dialogs can extend the
preferences super class. The second case may be benifical as you may be
writing similar code in each of your foo, bar, and baz preferences
classes that could be moved to the super class. Then you can create a
ImageChooserPanel with a constructor that takes the interface as an
argument or the super class.
That sounds like an excellent suggestion; I was just thinking that I should
have a PreferencesDialog class and subclass the other preference classes
from it. The getLocale() and getLogger() methods - and probably several
other things - would be common to all of them. But maybe you're right and I
should have a Preferences interface instead. In any case, this will give me
a good excuse to review the differences between classes and interfaces so
that I can choose between the alternatives :)

Thanks for your comments!

Rhino
 
R

Rhino

Tim Terry said:
why don't you create either a preferences interface which has
getLocale() and getLogger() methods which each specific preferences
dialog can implement. Or create a preferences super class which extends
jdialog then your specialized preferences dialogs can extend the
preferences super class. The second case may be benifical as you may be
writing similar code in each of your foo, bar, and baz preferences
classes that could be moved to the super class. Then you can create a
ImageChooserPanel with a constructor that takes the interface as an
argument or the super class.
I thought I'd like to try to take a stab at creating an interface with
getLocale() and getLogger() methods, as you suggested, but I've hit a
roadblock.

I created the interface and the two methods, which were, as required
abstract and final, calling the interface Fuzz, just for the moment, to keep
from clashing with any existing classes. Dead easy. I added Fuzz to the list
of interfaces that ImageChooserPanel implements. I added an import for
interface Fuzz to satisfy the compiler. The compiler insisted that I provide
a getLogger() method to implement the abstract one in Fuzz. (Curiously, it
doesn't insist that I also provide a getLocale() method, even though it was
also defined in Fuzz the same way as getLogger(). Any ideas why it doesn't
demand that one to be there too?)

Anyway, I created my getLogger method in ImageChooserPanel as follows:

public Logger getLogger() {

Logger myLogger = null;
return myLogger;
}

This satisfies the compiler since the method is now supplied but, of course,
only returns a null, not an actual Logger.

The roadblock is that I'm really not sure to write getLogger() so that it
obtains the Logger from the xxxPreferences class that created this instance
of ImageChooserPanel. I assume I need to pass something into the
ImageChooserPanel.getLogger() method via its input parameter but I'm not
sure *what* to pass or what class that parameter would be. If you - or
anyone else reading this - could give me that information, I would really
appreciate it!

Rhino
 
T

Tim Terry

Rhino said:
I thought I'd like to try to take a stab at creating an interface with
getLocale() and getLogger() methods, as you suggested, but I've hit a
roadblock.

I created the interface and the two methods, which were, as required
abstract and final, calling the interface Fuzz, just for the moment, to keep
from clashing with any existing classes. Dead easy. I added Fuzz to the list
of interfaces that ImageChooserPanel implements. I added an import for
interface Fuzz to satisfy the compiler. The compiler insisted that I provide
a getLogger() method to implement the abstract one in Fuzz. (Curiously, it
doesn't insist that I also provide a getLocale() method, even though it was
also defined in Fuzz the same way as getLogger(). Any ideas why it doesn't
demand that one to be there too?)

Anyway, I created my getLogger method in ImageChooserPanel as follows:

public Logger getLogger() {

Logger myLogger = null;
return myLogger;
}

This satisfies the compiler since the method is now supplied but, of course,
only returns a null, not an actual Logger.

The roadblock is that I'm really not sure to write getLogger() so that it
obtains the Logger from the xxxPreferences class that created this instance
of ImageChooserPanel. I assume I need to pass something into the
ImageChooserPanel.getLogger() method via its input parameter but I'm not
sure *what* to pass or what class that parameter would be. If you - or
anyone else reading this - could give me that information, I would really
appreciate it!

Rhino

If you are going to go down the interface route, something like this may
give you some ideas. Notice the preferences interface is passed as an
argument to the image chooser panel. When getLogger is called on the
IPreference interface the corresponding method of the implementing class
will be called. You would want to use inheritance instead if your
implementation classes have a lot of similarity.

public interface IPreferences{
public Logger getLogger();
public Locale getLocale();
}
public class FooPreferences implements IPreferences{
public Logger getLogger(){
/* some implementation*/
return Logger;
}
public Locale getLocale(){
/* some implementation*/
return Locale;
}
}
public class BarPreferences implements IPreferences{
public Logger getLogger(){
/* some implementation*/
return Logger;
}
public Locale getLocale(){
/* some implementation*/
return Locale;
}
}
public class ImageChooserPanel{
Logger logger;
Locale locale;
public ImageChooserPanel(IPreferences preferences){
logger = preferences.getLogger();
locale = preferences.getLocale();
}
}

Tim
 

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,780
Messages
2,569,611
Members
45,266
Latest member
DavidaAlla

Latest Threads

Top