Overloading abstract methods

C

Chris Uppal

Rhino said:
Going through this thought process again has made me change my mind! As I
wrote the preceding paragraph, I realized that it still bothered me to
pass
parameters that were being ignored and that this bothered me more than
having overloaded versions of the writeEmploymentHistory() method.

I think that the underlying problem here is that you are making the same
decision in two different places, and that is mucking-up the structure of your
code.

Basically, what you have is a framework for generating CVs. Your framework
code -- in the abstract ResumeWriter superclass "drives" the process, and the
"pluggable" code (implemented as concrete subclasses of ResumeWriter)
implements the actual formatting. That's fair enough as far as it goes (though
I'll mention that it has a distinctly procedural flavour to my mind [*]). But
the problem comes when you try to decide /what/ data to print. You are
attempting to make that decision in the driver (which is not unreasonable), but
then you hit the problem that that decision can only be made with knowledge of
the capabilities of the concrete document format (HTML has tables, ASCII text
does not). So although you /want/ your driver to abstract away from the
details of the concrete representation, in this case it cannot do so. So you
end up with the "knowledge" about how the employment history is represented in
two different places. In one place (in the driver) you select which of the two
methods to invoke (the simple or complete versions). In another place (in the
various subclasses) you duplicate that knowledge by the choice of which of the
two method to provide a real implementation for.

([*] I can talk more about that if you are interested.)

In this case, that's (IMO) because you are trying to make the "driver" do too
much. If it did not know about the details of /what/ data was shown in an
employment history then there would be no problem. More specifically still, if
it did not /choose/ what data to display and pass that to the implementation
method, then there would be no problem. I understand that the reason you have
been lead to this position is to avoid the code duplication that would
otherwise occur, but that is leading you astray (I think). Code duplication is
not -- in itself -- bad. It's only bad when code is duplicated that is
/necessarily/ the same in both places. That's to say if one version changed
then the other /must/ change too. And in this case, the code duplication is
accidental rather than necessary -- it's only an accident that (say) the PDF
generator will display the same data as the HTML generator. So the fact that
the PDF generator and HTML generator use the same accessors to find the
employment history is not in itself an indicator of a problem. (Although there
is probably scope for factoring out some utility code which can be shared
between them).

Just because there is common code in (some of) the concrete subclasses does
/not/ mean that you must move that code into the driver. Certainly you should
consider whether it is appropriate to do so, but that decision should be based
on whether that code should reasonably be expected to live in the driver --
whether it is part of the design of the driver-- the question is not whether it
/can/ but whether it /must/.

Oh, by the way, I would take the large number of parameters (six) to this
method to be another hint that the design is ill-balanced. If the driver code
were not trying to do too much, then it would not be extracting all that data
from the raw input, and so would not need to pass it to the writing methods.

-- chris
 
C

Chris Uppal

Chris said:
Option 1: ResumeWriter is conceived of as a tool. You could create one
without giving it any specific information about any particular person's
resume. It has a method to write a resume, and all necessary
information is passed in there. [...]

Option 2: A ResumeWriter is a one-shot object that's used to write a
specific resume. It's created to write one resume and then discarded.
[...]

Both options are fine.

Though I'd argue that (1) is in general inferior to (2). It depends on cases,
of course, but usually (2) is simpler to use and think about, easier to
implement, and more flexible. So I'd recommend (2) as the norm, with (1) as an
alternative to use in the (relatively rare) cases where it turns out to be more
appropriate.

-- chris
 
A

Andrew McDonagh

Chris said:
Rhino wrote:

Going through this thought process again has made me change my mind! As I
wrote the preceding paragraph, I realized that it still bothered me to
pass
parameters that were being ignored and that this bothered me more than
having overloaded versions of the writeEmploymentHistory() method.


I think that the underlying problem here is that you are making the same
decision in two different places, and that is mucking-up the structure of your
code.

Basically, what you have is a framework for generating CVs. Your framework
code -- in the abstract ResumeWriter superclass "drives" the process, and the
"pluggable" code (implemented as concrete subclasses of ResumeWriter)
implements the actual formatting. That's fair enough as far as it goes (though
I'll mention that it has a distinctly procedural flavour to my mind [*]). But
the problem comes when you try to decide /what/ data to print. You are
attempting to make that decision in the driver (which is not unreasonable), but
then you hit the problem that that decision can only be made with knowledge of
the capabilities of the concrete document format (HTML has tables, ASCII text
does not). So although you /want/ your driver to abstract away from the
details of the concrete representation, in this case it cannot do so. So you
end up with the "knowledge" about how the employment history is represented in
two different places. In one place (in the driver) you select which of the two
methods to invoke (the simple or complete versions). In another place (in the
various subclasses) you duplicate that knowledge by the choice of which of the
two method to provide a real implementation for.

([*] I can talk more about that if you are interested.)

In this case, that's (IMO) because you are trying to make the "driver" do too
much. If it did not know about the details of /what/ data was shown in an
employment history then there would be no problem. More specifically still, if
it did not /choose/ what data to display and pass that to the implementation
method, then there would be no problem. I understand that the reason you have
been lead to this position is to avoid the code duplication that would
otherwise occur, but that is leading you astray (I think). Code duplication is
not -- in itself -- bad. It's only bad when code is duplicated that is
/necessarily/ the same in both places. That's to say if one version changed
then the other /must/ change too. And in this case, the code duplication is
accidental rather than necessary -- it's only an accident that (say) the PDF
generator will display the same data as the HTML generator. So the fact that
the PDF generator and HTML generator use the same accessors to find the
employment history is not in itself an indicator of a problem. (Although there
is probably scope for factoring out some utility code which can be shared
between them).

Just because there is common code in (some of) the concrete subclasses does
/not/ mean that you must move that code into the driver. Certainly you should
consider whether it is appropriate to do so, but that decision should be based
on whether that code should reasonably be expected to live in the driver --
whether it is part of the design of the driver-- the question is not whether it
/can/ but whether it /must/.

Oh, by the way, I would take the large number of parameters (six) to this
method to be another hint that the design is ill-balanced. If the driver code
were not trying to do too much, then it would not be extracting all that data
from the raw input, and so would not need to pass it to the writing methods.

-- chris

I'd say the problems comes from trying to use inheritence to solve a
problem that delegation is better suited to.

From whats been posted, I'd say have the concrete drivers classes as
strategy objects and the abstract base class being a normal concrete
driving class, would be a better design.

Each strategy class then gets the specific data it needs from the single
'model'? concrete class.

as in...

driver::createResume() {
for each Strategy
strategy.createResume(this);
}


my 2 cents

Andrew
 
O

Oliver Wong

Andrew McDonagh said:
I'd say the problems comes from trying to use inheritence to solve a
problem that delegation is better suited to.

Yes, I agree. It seems like the only thing Rhino's abstract super class
does is provides a unified way of reading the data. That class should be
renamed into "ResumeData" or something like that, and then passed into the
resume-writing objects. The resume-writing objects query the DataReader to
get the information they want, and write whatever they want. A quick sketch
of the design might be something like:

<pseudocode>
class ResumeData {
public ResumeData(File resumeFile) {
/*
* Read in the data, populate the fields of this class.
*/
}

public String getName() {
return this.name;
}

public EmploymentHistory getEmploymentHistory() {
return this.employmentHistory;
}
}

interface ResumeWriter {
public void write(ResumeData data);
}

class PDFResumeWriter implements ResumeWriter {
public PDFResumeWriter(File outputFile) {
this.outFile = outputFile;
}

public void write(ResumeData data) {
openReadersOn(this.outFile)
getDataFrom(data);
writeDataTo(this.outFile);
}
}
</pseudocode>

- Oliver
 
C

Chris Smith

Chris Uppal said:
Though I'd argue that (1) is in general inferior to (2). It depends on cases,
of course, but usually (2) is simpler to use and think about, easier to
implement, and more flexible. So I'd recommend (2) as the norm, with (1) as an
alternative to use in the (relatively rare) cases where it turns out to be more
appropriate.

Funny. I was thinking exactly the opposite; i.e., that (1) is the more
normal and the easier to think about... hence my numbering is "1".

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Andrew McDonagh said:
I'd say the problems comes from trying to use inheritence to solve a
problem that delegation is better suited to.

From whats been posted, I'd say have the concrete drivers classes as
strategy objects and the abstract base class being a normal concrete
driving class, would be a better design.

Obviously, neither of us has the whole story. Still, my intuition here
tells me that's not the problem. This seems to be a straight-forward
and reasonable use of inheritance.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Oliver Wong said:
Yes, I agree. It seems like the only thing Rhino's abstract super class
does is provides a unified way of reading the data.

The other thing (the more important thing, in fact) that the abstract
superclass is doing is to call methods to write the pieces of the
resume. A method like "writeResume" would exist in the parent, and it
calls overridden methods to write each section in turn.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Uppal

Chris Smith wrote:

[me:]
Though I'd argue that (1) is in general inferior to (2). [..]

Funny. I was thinking exactly the opposite; i.e., that (1) is the more
normal and the easier to think about... hence my numbering is "1".

You astonish me!

-- chris
 
C

Chris Uppal

Andrew said:
[me:]
I think that the underlying problem here is that you are making the same
decision in two different places, and that is mucking-up the structure
of your code.

I'd say the problems comes from trying to use inheritence to solve a
problem that delegation is better suited to.

I don't agree.

I do agree that, if I'd been programming this, there would be at least two
separate objects (or maybe three), but I don't think that delegation would be
quite the way to describe the relationship between them. The relationship
would just be a normal pairing of objects (each with a different set of
responsibilities, and corresponding different capabilities) which co-operate to
achieve some end-result.

More importantly, I don't think that splitting this problem into two objects
would materially change the specific design issue that has been giving Rhino
problems. In his design the superclass (the "driver" in my terms) is conceived
of as being a separate "entity" from the specific subclass (the pluggable
"driven" bit). There is a clear separation between the purpose of the
superclass code and that of the subclass code, even though both "entities"
coexist in one Java object. Personally, I would have chosen to express that
separation by using two objects, but that isn't how Rhino has chosen to factor
the problem -- he has chosen to use the technical toolkit of OO (specifically
subclassing and polymorphically overridden methods) to create a perfectly valid
(albeit not terribly OO) design where that separation is expressed by software
layering /within/ one object. If the "driver" and the "driven" were two
different Java objects (as I would set it up), there would /still/ be the
question of which object was responsible for deciding which data should be
displayed in an employment history, and that would still depend on the specific
document format. Using "true" OO would not magically solve that problem. It
is a genuine design problem, inherent in the problem-space, rather than just a
side-effect of the way Rhino is using the available tools.

I believe that a more OO approach to this design would make it easier to see,
and thus to solve, the problem -- naturally, I'm a hard-core OOer -- but I
don't believe that Rhino's overall approach has /created/ the problem.

-- chris
 
O

Oliver Wong

Chris Smith said:
The other thing (the more important thing, in fact) that the abstract
superclass is doing is to call methods to write the pieces of the
resume. A method like "writeResume" would exist in the parent, and it
calls overridden methods to write each section in turn.

But presumably each type of resume (the PDF, HTML, etc.) might have a
different set of sections (I believe Rhino mentioned he doesn't want the
employment history in the ASCII version or something like that), so the
generic writeResume() wouldn't know what set of methods to call anyway, and
would thus probably just be abstract and body-less. In which case, again, I
think it makes more sense to define an interface with a single writeResume()
method.

- Oliver
 
C

Chris Smith

Oliver Wong said:
But presumably each type of resume (the PDF, HTML, etc.) might have a
different set of sections (I believe Rhino mentioned he doesn't want the
employment history in the ASCII version or something like that), so the
generic writeResume() wouldn't know what set of methods to call anyway, and
would thus probably just be abstract and body-less. In which case, again, I
think it makes more sense to define an interface with a single writeResume()
method.

If that's the case, then it changes things of course. What was really
said, though, is that the employment history should look different
depending on the type of resume. Different formats would need different
information fields... but the list of sections doesn't change.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Rhino

Chris Smith said:
Rhino said:
Okay, so what are you saying I should do to prevent these problems? I
know
the compiler will not let me make writeEmploymentHistory() (within
ResumeWriterAscii) a private method because it is public in the abstract
class and the implementation can't have less access than the abstract
version. I know the compiler will only let me make the method public or
protected in the abstract class. I _can_ make writeEmploymentHistory()
final
within ResumeWriterAscii; is that what you are suggesting? I don't plan
on
subclassing ResumeWriterAscii or its siblings any further so I don't have
a
problem with making the writeXXX() implementations final.

I mean that any method you call from a constructor should be either
private or final in the class where you call it. Since you need to
override writeEmploymentHistory, that precludes the possibility of
calling writeEmploymentHistory from the constructor. An alternative
design is:

public class ResumeWriter
{
private ResourceBundle locList;

public ResumeWriter(ResourceBundle locList)
{
this.locList = locList;
}

public void writeResume()
{
String employmentHistoryText = ...;
String[][] employmentHistoryData = ...;

writeEmploymentHistory(
employmentHistoryText, employmentHistoryData);
}
}
Okay, I can see some virtues to making ResumeWriter a concrete class rather
than an abstract one. For example, locList becomes an instance variable so I
don't need to pass it to each method in the concrete ResumeWriter. But I'm
not clear from your fragment about a few things:
- Am I correct in assuming that my getters will still exist as separate
methods in the concrete versio of ResumeWriter? You're not proposing that I
should take the work done by the getters and move them into the
writeResume() method are you?
- Are you proposing that I write a single version of
writeEmploymentHistory(), presumably the six-parameter version, or two
versions, one that has two parameters and one that has six parameters? - Am
I correct in understanding that the implementation(s) of
writeEmploymentHistory need to be complete? Since ResumeWriter is not an
abstract class any more, I believe I have to make each implementation
concrete. But what format will my implemenation write: HTML or ASCII or PDF?

If you can answer these last two questions, it will go a long way to helping
me understand exactly what you're proposing.
There are now two steps to writing a resume: first, create a
ResumeWriter, and then call its writeResume method. That's better,
anyway. It's surprising when writing the resume -- which is the main
purpose of a ResumeWriter -- is done as a side-effect of creating the
object. If other people were using this API, it would take them time to
get accustomed to that little quirk, and it prevents the code from
reading well. There is no mental model of the ResumeWriter class that
makes it logical for it to write the resume in the constructor.

Note that this paves the way for the changes suggested elsewhere. What
needs to happen now is:

- your getEmploymentHistoryText and getEmploymentHistoryData methods
made protected, so that they can be accessed by the subclass, and
modified so that they get locList from the instance field rather than a
parameter.
Okay, so you do mean for me to leave the getters as standalone concrete
methods. Good, that makes sense to me.
- All parameters removed from writeEmploymentHistory. Implementations
of writeEmploymentHistory in the subclass should call
getEmploymentHistoryText and getEmploymentHistoryData directly if they
need that information.
So all the values obtained from my getters become instance variables. Okay,
that's fine. Should these instance variables be public, protected or
private?
It's a quirk of the implementation. The superclass constructor runs
before the subclass constructor... and a polymorphic call to a method
(like writeEmploymentHistory) from the superclass constructor can
therefore reach the subclass before its constructor is called. The
typical way to avoid this is to make sure that all methods called from a
constructor are private or final, so that they can't be overridden.


In Eclipse, I assume? I don't believe that warning exists.


I'm confused by your use of the term "class variable". When most people
say "class variable" or "class field", they mean a static field. My
example didn't use any static fields (although it would probably be
incorrect to set them from a constructor, if you did have one).
Sorry, that was my fault for misusing the terminology. When I used the term
'class variable', I should have said 'instance variable'; I got the two
terms muddled.
My warning was against calling polymorphic (that is, non-final and non-
private) methods from a constructor.
Okay, I'll watch for that from now on.
Again, I've mischaracterized these as class variables when they are actually
instance variables. Sorry!
They get set to useful values in the constructor and are then used
throughout the class. I'm not going to have any problems with any of
that,
am I?

Well, in the code you posted, writeEmploymentHistory is going to be
called BEFORE the constructor for ResumeWriterAscii... so you very well
might have problems. Both variables will be null -- and not because you
set them to null above, but because all reference variables will be
null.
The compiler is not giving me any errors or warnings anywhere in my
project.

As I said, I don't think Eclipse has a warning for this one.
Hmmm, just out of curiousity, I made a class variable called strOutfile
which was defined as a private String and initialized to null. Then,
within
my constructor, I added this line:

this.strOutfile = strOutfile;

I also added this line to writeEmploymentHistory():

System.out.println("strOutfile: " + this.strOutfile); //$NON-NLS-1$

The compiler flags 'strOutfile' within my constructor signature ['public
ResumeWriterAscii(String strOutfile, ResourceBundle locList)'] and gives
me
this warning: "The parameter strOutfile is hiding a field from type
ResumeWriterAscii." That's fair enough since the strOutfile value passed
in
via the constructor will inevitably clobber the value of the strOutfile
class variable.

The warning you're getting is not related to this problem. It's just
saying that you're hding a field with a parameter. To get rid of it,
just rename the parameter.
Sorry, that was a red herring.
 
R

Rhino

Chris Uppal said:
Chris Smith wrote:

[me:]
Though I'd argue that (1) is in general inferior to (2). [..]

Funny. I was thinking exactly the opposite; i.e., that (1) is the more
normal and the easier to think about... hence my numbering is "1".

You astonish me!
I suppose one man's normal is another man's bizarre - and vice versa :)

Rhino
 
R

Rhino

Chris Uppal said:
Rhino said:
Going through this thought process again has made me change my mind! As I
wrote the preceding paragraph, I realized that it still bothered me to
pass
parameters that were being ignored and that this bothered me more than
having overloaded versions of the writeEmploymentHistory() method.

I think that the underlying problem here is that you are making the same
decision in two different places, and that is mucking-up the structure of
your
code.

Basically, what you have is a framework for generating CVs. Your
framework
code -- in the abstract ResumeWriter superclass "drives" the process, and
the
"pluggable" code (implemented as concrete subclasses of ResumeWriter)
implements the actual formatting. That's fair enough as far as it goes
(though
I'll mention that it has a distinctly procedural flavour to my mind [*]).

Not surprising given my background with procedural programming ;-) It's a
hard mindset to overcome, at least for me!
But
the problem comes when you try to decide /what/ data to print. You are
attempting to make that decision in the driver (which is not
unreasonable), but
then you hit the problem that that decision can only be made with
knowledge of
the capabilities of the concrete document format (HTML has tables, ASCII
text
does not). So although you /want/ your driver to abstract away from the
details of the concrete representation, in this case it cannot do so. So
you
end up with the "knowledge" about how the employment history is
represented in
two different places. In one place (in the driver) you select which of
the two
methods to invoke (the simple or complete versions). In another place (in
the
various subclasses) you duplicate that knowledge by the choice of which of
the
two method to provide a real implementation for.
Yes, that seems like a pretty accurate analysis.
([*] I can talk more about that if you are interested.)

In this case, that's (IMO) because you are trying to make the "driver" do
too
much. If it did not know about the details of /what/ data was shown in an
employment history then there would be no problem. More specifically
still, if
it did not /choose/ what data to display and pass that to the
implementation
method, then there would be no problem. I understand that the reason you
have
been lead to this position is to avoid the code duplication that would
otherwise occur, but that is leading you astray (I think). Code
duplication is
not -- in itself -- bad. It's only bad when code is duplicated that is
/necessarily/ the same in both places. That's to say if one version
changed
then the other /must/ change too. And in this case, the code duplication
is
accidental rather than necessary -- it's only an accident that (say) the
PDF
generator will display the same data as the HTML generator. So the fact
that
the PDF generator and HTML generator use the same accessors to find the
employment history is not in itself an indicator of a problem. (Although
there
is probably scope for factoring out some utility code which can be shared
between them).
Actually, I've created a concrete ResumeUtilities class to do a few things
that most of the file generator classes need to do, including those that are
NOT subclasses of ResumeWriter (which is still an abstact class as I write
this). The ResumeUtilities class has static methods that do the following:
- delete the old version of the file
- open the output file (essentially, gets a PrintWriter reference for the
physical file that is being written)
- close the output file (flushes and closes the PrintWriter)
- create a 'generatedBy' String that is written to most of the files
identifying the name of the class that generated the file and the date and
time when the file was generated.

This avoids considerable duplication within the various file generator
classes. I was initially tempted to put these methods in ResumeWriter but I
immediately realized that they were used by several classes that aren't
descended from ResumeWriter, so I spun off a separate class for these
methods.
Just because there is common code in (some of) the concrete subclasses
does
/not/ mean that you must move that code into the driver. Certainly you
should
consider whether it is appropriate to do so, but that decision should be
based
on whether that code should reasonably be expected to live in the
driver --
whether it is part of the design of the driver-- the question is not
whether it
/can/ but whether it /must/.
It wouldn't make sense to put the two different writeEmploymentHistory()
methods in ResumeUtilities, right? You're basically saying that it's okay
that ResumeWriterAscii and ResumeWriterPdf use the two parameter version of
writeEmploymentHistory() but have different implementations and that
ResumeWriterHtml uses the six-parameter version of writeEmploymentHistory()
and has yet another concrete implementation, right?
Oh, by the way, I would take the large number of parameters (six) to this
method to be another hint that the design is ill-balanced. If the driver
code
were not trying to do too much, then it would not be extracting all that
data
from the raw input, and so would not need to pass it to the writing
methods.
Arggghhh! For every step forward, there seems to be at least one step back!!
Now I need to redesign because I've got excessive parameters in some
methods....

Well, it's hardly surprising and I'm not trying to shoot the messenger; I
get uneasy when I have methods that have large numbers of parameters. One of
my methods, writeSoftwareSkills(), has 13 parameters! But I could break this
method up into 7 smaller methods, one that has a single parameter and six
that have two parameters each, e.g. writeProgrammingLanguages(String text,
String data), writeDatabases(String text, String data), writeIDEs(String
text, String data), etc.

But breaking up writeEmploymentHistory() is considerably harder because all
of that data relates to positions that I've held in the past. Frankly, I'm
strongly inclined to leave it alone. I just don't have any more time to
diddle around with this. I _have_ to start my job search this week.

Rhino
 
R

Rhino

Chris Smith said:
If that's the case, then it changes things of course. What was really
said, though, is that the employment history should look different
depending on the type of resume. Different formats would need different
information fields... but the list of sections doesn't change.
You're right Chris; Oliver has misunderstood: each "section" of the resume
(name, job target, employment history, etc. ) appears in every format of the
resume. The exact appearance of a given section will vary slightly in some
resumes though, as you (Chris) has understood.

For instance, the HTML version will look (roughly!!) like this (picture a
table to contain the data):

EMPLOYMENT HISTORY

From/To Employer Role Main Tools
2003/2005 IBM Programmer Java, DB2
Developed programs for XYZ department

2001/2003 Foo Corp Programmer COBOL, IMS
Developed programs for ABC department


The ASCII version will be very similar but omit the "From/To Employer Role
Main Tools" heading and, of course, it won't be drawn in a table.

The PDF version will also omit the "From/To..." heading but each job will be
a separate box.

So, the content of the Employment History is essentially identical in each
case; only the presence or absence of that one heading distinguishes the
resumes. But the layout of the data is quite different in each case.


Rhino
 
C

Chris Uppal

[I have to leave the mess of attributions in place here -- I've trimmed a few
inessentials]
I suppose one man's normal is another man's bizarre - and vice versa :)

Indeed. What surprised me was not that /someone/ would prefer to (1) to (2) --
which is inevitable -- but that /Chris Smith/ would. I'm still puzzled...

-- chris
 
C

Chris Smith

Rhino said:
For instance, the HTML version will look (roughly!!) like this (picture a
table to contain the data):

EMPLOYMENT HISTORY

From/To Employer Role Main Tools
2003/2005 IBM Programmer Java, DB2
Developed programs for XYZ department

2001/2003 Foo Corp Programmer COBOL, IMS
Developed programs for ABC department


The ASCII version will be very similar but omit the "From/To Employer Role
Main Tools" heading and, of course, it won't be drawn in a table.

I had misunderstood slightly, then. As far as I can tell (correct me if
I'm wrong), the table headers are not really resume-dependent data. You
don't need to pass them into anything. Hard-coding English strings for
the table headers is still perhaps a bad idea, but just have your HTML
subclass get them from a ResourceBundle instead of trying to have the
ResumeWriter superclass know about them. The only data you should make
available via the superclass is that which is specific to a single
resume.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Smith

Chris Uppal said:
Indeed. What surprised me was not that /someone/ would prefer to (1) to (2) --
which is inevitable -- but that /Chris Smith/ would. I'm still puzzled...

I don't know what to say. I suppose I'm just weird.

I almost included a warning against "option 2", saying that if you do it
that way, it would be better to call the object Resume instead of
ResumeWriter, since one of its two purposes is to organize the data that
belongs to a resume. Then I'd suggest collapsing the data into a single
concrete Resume class and factoring out the format-specific writing
parts into a different class hierarchy. Once that's done, we're back at
option 1.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
R

Rhino

Chris Smith said:
I had misunderstood slightly, then.

Not as much as Oliver though :)
As far as I can tell (correct me if
I'm wrong), the table headers are not really resume-dependent data. You
don't need to pass them into anything. Hard-coding English strings for
the table headers is still perhaps a bad idea, but just have your HTML
subclass get them from a ResourceBundle instead of trying to have the
ResumeWriter superclass know about them.

I'm not sure what you mean by resume-dependent data. The table headers,
specificially the text strings "From/To", "Employer", "Role", and "Main
Tools", already come from a ResourceBundle since I may want to change their
precise wording; for example, I may want to change "Main Tools" to "Main
Tools Used" and I'd like to only have to change the ResourceBundle, not the
coding in the ResumeWriter class or ResumeWriter subclass. At present, while
ResumeWriter is an abstract class - you haven't yet sold me on the virtues
of making it a concrete class - I have a getter for each of those 4 Strings.
Those then are the 4 "extra" Strings that distinguish the two versions of
writeEmploymentHistory().

I _could_ modify the ResumeWriterHtml class so that its
writeEmploymentHistory() method gets the 4 extra Strings directly; then the
abstract ResumeWriter would only need the two-parameter
writeEmploymentHistory() method and the subclasses would only need to
implement that one version of the method. Then the writeEmploymentHistory()
method would be self-sufficient in ResumeWriterAscii and ResumeWriterPdf,
i.e. it wouldn't need anything but what was passed in via its parameters,
plus any existing instance variables in the class. However, the
writeEmploymentHistory() method in ResumeWriterHtml would need to get those
4 supplemental fields directly. That's not necessarily bad but I liked the
fact that all of the information was being obtained in the concrete getters
of ResumeWriter; that consistency would be gone if ResumeWriterHtml starts
doing its own gets against the ResourceBundle. Is is bad design to do some
of the getting at the subclass level and some at the abstract class level?
The only data you should make
available via the superclass is that which is specific to a single
resume.
Sorry? I don't follow. That seems to be exact opposite of what I'm doing
now; _all_ of the data I'm writing in the ResumeWriter subclasses was
supplied by getters in the ResumeWriter class. The only data that is
specific to one resume is the 4 extra Strings and you just finished telling
me to get them directly in the subclass, not the superclass.

Also, I'm really eager to see your reply to my remarks of 11/01/2006 12:34
PM; I had some key followup questions but it looks like you've missed them
in this increasingly packed thread. Those answers will help me understand
why ResumeWriter should be concrete instead of abstract and make it clear
whether I should have one or two versions of getEmploymentHistory().

Rhino
 
P

P.Hill

Roedy Green wrote about putting modifiers on the end of a class name.
the advantage of doing that weird way is javadoc listings will put the
three classes side by side.
They would at least sort nicely in (my) IDEs list's of classes.

Just to pick this slightly old thread. Let's see, something that can
group things together. How about a package! Now that was simple enough.

If you didn't want them all in their own package, I'd wonder what
the list of other things were in the package that is making it so
cluttered that you can't see the three classes.

Also IDEs with inheritance hierarchies are cool tools also.

Yeah, I'm with Chris, adjectives in English go _before_ the noun!

"Scoping" modifiers in names are for programming in assembly no Java or
C++

-Paul
 

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,772
Messages
2,569,593
Members
45,108
Latest member
AlbertEste
Top