Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #12760 > unrolled thread
| Started by | Novice <novice@example..com> |
|---|---|
| First post | 2012-03-08 00:27 +0000 |
| Last post | 2012-03-11 23:29 +0000 |
| Articles | 7 — 3 participants |
Back to article view | Back to comp.lang.java.programmer
Designing Interfaces Novice <novice@example..com> - 2012-03-08 00:27 +0000
Re: Designing Interfaces Arved Sandstrom <asandstrom3minus1@eastlink.ca> - 2012-03-08 08:28 -0400
Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 09:11 -0500
Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 09:35 -0500
Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 19:24 -0500
Re: Designing Interfaces Jeff Higgins <jeff@invalid.invalid> - 2012-03-08 19:36 -0500
Re: Designing Interfaces Novice <novice@example..com> - 2012-03-11 23:29 +0000
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-08 00:27 +0000 |
| Subject | Designing Interfaces |
| Message-ID | <XnsA00FC7119110Ajpnasty@94.75.214.39> |
This is actually a discussion that Lew and I started in the "Aspect Qustions" thread but it is so unwieldy know that I'm pushing it into a new thread. Here's the context so that everyone knows what the subject of discussion is. While this started as sort of a side conversation between Lew and I, as far as I'm concerned, anyone who has something to contribute is more than welcome to jump in on this. Even if you say the same thing as someone else, your wording might be more effective in making me see the point than the way the other person said it. Anyway, here's where we were in the other thread. >>>>> Summary: >>>>> Interface: what to do >>>>> Class: how to do it > ... >>> Give me an example of some unit of functionality you'd like to >>> design, in broad terms, and I'll do just that. >> I think that would be an interesting exercise. Let's do one that I've >> already done myself and that you (probably) haven't. I'm sure I'll >> learn some things by seeing how you approach it. >> I have a project (that regularly undergoes polishing) to produce >> resumes. More specifically, it creates various formats of my own >> resume (and only my own resume.) Each of the resumes I generate >> contains the exact same information obtained from a single file but I >> generate it in several formats: an HTML version, a Java applet, an >> ASCII text version, a PDF version (using iText), and a Word version. >> I also generate supporting files, including a CSS file for the HTML >> version of the resume, and a short PDF containing contact information >> for references. > What are the overall modules? For example: "Obtain resume from single > file", "Export to format X", "Generate references document", ... At the moment, I have a main program that simply generates each document in turn. It's called ResumeFileGenerator. Its constructor gets the resource bundle that drives the creation of the resumes. Each resume format is generated by a separate class and is passed an object that represents the data needed in the resume and the path and file name to be generated by that class. Then, the supporting documents are each generated by their own separate classes. They too are told the path and file name that should be generated but are not passed the resume object since they don't need it. >> The program that generates the resumes and supporting files is >> written in Java. The data file that is parsed to create each format >> of the resume is a Java ResourceBundle of the "list" type. NOw, I'm >> only producing the resumes > Sorry, "list" type? Sorry, that was sloppy shorthanding on my part. I meant the ResourceBundles that are based on ListResourceBundles, as shown at http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html, versus the "text" and "message" types which are basically properties files. Some of my data consists of arrays like the list of editors I've used and the list of word processing programs I'm familiar with so the simpler property file type resource bundles don't work well for that. >> in English so I should mention that I am open to the possibility of >> creating the resume in additional languages - I have a working >> knowledge of two other (human) languages - so I chose to use a >> Resource Bundle so that I could easily generate resumes in additional >> languages. Otherwise, I'd have probably just used a standard text >> file or more likely a properties file. >> Given the fact that several resumes containing the same data are >> being generated there would seem to be obvious opportunities for >> refactoring and probably at least one interface. This code has gone >> through various permutations but I've used a single interface with a >> single method in my existing code. The code works but I'm not at all >> sure it is designed well. > What interface? What method? It's an interface I created as opposed to one that is in the API. It is called ResumeFileWriter and has one empty method in it called writeResume. It has two parameters, a String that identifies the path and name of the file to be written and a Resume object that refers to the data contained in the Resource Bundle. Each of the classes that writes an actual resume (as opposed to a supporting file) implements it. It's entirely likely that this interface should do a lot more than it currently does. That's why I'm very curious to get your take on this. I've also got an abstract class called ResumeFileCreator. It has four concrete methods: deleteFile, openOutputFile, closeOutputFile and getGeneratedBy (which simply generates a string containing the name of a class and the current date and time which I use to create comments in each of the files that are written). Each of the classes that writes a resume or supporting file subclasses ResumeFileCreator. >> I'd be very curious to get your take on it. I expect that the design >> has major flaws and I'd like to clean those up once I find out what >> they are. >> Does that sound reasonable to you? I'm basically asking you to talk >> me through the way you would design it knowing what I've told you. >> Naturally, you're free to ask as many questions as you like to >> understand what I'm trying to do. > We'll go step by step. Works for me :-) -- Novice
[toc] | [next] | [standalone]
| From | Arved Sandstrom <asandstrom3minus1@eastlink.ca> |
|---|---|
| Date | 2012-03-08 08:28 -0400 |
| Message-ID | <JB16r.1675$M%7.503@newsfe10.iad> |
| In reply to | #12760 |
On 12-03-07 08:27 PM, Novice wrote: > This is actually a discussion that Lew and I started in the "Aspect > Qustions" thread but it is so unwieldy know that I'm pushing it into a > new thread. > > Here's the context so that everyone knows what the subject of discussion > is. While this started as sort of a side conversation between Lew and I, > as far as I'm concerned, anyone who has something to contribute is more > than welcome to jump in on this. Even if you say the same thing as > someone else, your wording might be more effective in making me see the > point than the way the other person said it. Anyway, here's where we were > in the other thread. > > >>>>>> Summary: >>>>>> Interface: what to do >>>>>> Class: how to do it >> ... >>>> Give me an example of some unit of functionality you'd like to >>>> design, in broad terms, and I'll do just that. > >>> I think that would be an interesting exercise. Let's do one that I've >>> already done myself and that you (probably) haven't. I'm sure I'll >>> learn some things by seeing how you approach it. > >>> I have a project (that regularly undergoes polishing) to produce >>> resumes. More specifically, it creates various formats of my own >>> resume (and only my own resume.) Each of the resumes I generate >>> contains the exact same information obtained from a single file but I >>> generate it in several formats: an HTML version, a Java applet, an >>> ASCII text version, a PDF version (using iText), and a Word version. >>> I also generate supporting files, including a CSS file for the HTML >>> version of the resume, and a short PDF containing contact information >>> for references. > >> What are the overall modules? For example: "Obtain resume from single >> file", "Export to format X", "Generate references document", ... > > At the moment, I have a main program that simply generates each document > in turn. It's called ResumeFileGenerator. Its constructor gets the > resource bundle that drives the creation of the resumes. Each resume > format is generated by a separate class and is passed an object that > represents the data needed in the resume and the path and file name to be > generated by that class. Then, the supporting documents are each > generated by their own separate classes. They too are told the path and > file name that should be generated but are not passed the resume object > since they don't need it. > >>> The program that generates the resumes and supporting files is >>> written in Java. The data file that is parsed to create each format >>> of the resume is a Java ResourceBundle of the "list" type. NOw, I'm >>> only producing the resumes > >> Sorry, "list" type? > > Sorry, that was sloppy shorthanding on my part. I meant the > ResourceBundles that are based on ListResourceBundles, as shown at > http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html, versus > the "text" and "message" types which are basically properties files. Some > of my data consists of arrays like the list of editors I've used and the > list of word processing programs I'm familiar with so the simpler > property file type resource bundles don't work well for that. > >>> in English so I should mention that I am open to the possibility of >>> creating the resume in additional languages - I have a working >>> knowledge of two other (human) languages - so I chose to use a >>> Resource Bundle so that I could easily generate resumes in additional >>> languages. Otherwise, I'd have probably just used a standard text >>> file or more likely a properties file. > >>> Given the fact that several resumes containing the same data are >>> being generated there would seem to be obvious opportunities for >>> refactoring and probably at least one interface. This code has gone >>> through various permutations but I've used a single interface with a >>> single method in my existing code. The code works but I'm not at all >>> sure it is designed well. > >> What interface? What method? > > It's an interface I created as opposed to one that is in the API. It is > called ResumeFileWriter and has one empty method in it called > writeResume. It has two parameters, a String that identifies the path and > name of the file to be written and a Resume object that refers to the > data contained in the Resource Bundle. Each of the classes that writes an > actual resume (as opposed to a supporting file) implements it. > > It's entirely likely that this interface should do a lot more than it > currently does. That's why I'm very curious to get your take on this. > > I've also got an abstract class called ResumeFileCreator. It has four > concrete methods: deleteFile, openOutputFile, closeOutputFile and > getGeneratedBy (which simply generates a string containing the name of a > class and the current date and time which I use to create comments in > each of the files that are written). Each of the classes that writes a > resume or supporting file subclasses ResumeFileCreator. > >>> I'd be very curious to get your take on it. I expect that the design >>> has major flaws and I'd like to clean those up once I find out what >>> they are. > >>> Does that sound reasonable to you? I'm basically asking you to talk >>> me through the way you would design it knowing what I've told you. >>> Naturally, you're free to ask as many questions as you like to >>> understand what I'm trying to do. > >> We'll go step by step. > > Works for me :-) > Given all that, I prefer a design where the "resume" objects know how to do things. If you start thinking of "writers" and "creators" you're headed towards Martin Fowler's Anemic Domain Model (look it up) and you're becoming quite procedural. Sure we've got a whole menagerie of Writers and Readers in core Java APIs, but these are nuts and bolts _implementation_ classes and interfaces. "Writers" and "Readers" in your own designs aren't illegal but you want to think things through carefully before deciding that they are the best solution. Start with your domain entity, Resume. Maybe that's what ought to be an interface. I'm just thinking aloud, this would be my first approach. What would I want a Resume to be able to do? I suspect it ought to be able to "write" itself: rather than "writeResume" in "ResumeFileCreator", maybe you've got "write" in "Resume". Hmmm, different formats? We'll be thinking design patterns in a bit. But first off, it seems a reasonable conclusion that Resume, not some file format library, knows how to convert itself to an abstract layout. Regardless of whether the final format is PDF or HTML or Word or XML, the Resume knows how to describe its output layout in terms of headers and footers and paragraphs and so forth. The nuances of this are open for vigorous debate, and I'll revisit this below (see Layout vs Logical Structure). So for writing a Resume, my first picture would be that when instructed to write itself, a Resume object can decompose itself into abstract write sub-operations: write the header, write the body, etc. These in turn have smaller bits. What are other choices? We have things like style of resume: skills-oriented, chronology-oriented etc. Resume can certainly deal with these (again, see Layout vs Logical Structure below). We also have things like does the format support pagination, and what is the output footprint (mobile screen, standard page etc), but this is not a Resume concern necessarily. Now, while Resume conceptually also knows everything about how to convert itself to PDF or HTML or Word, and nothing else does, you don't want Resume tied to a fixed set of output format choices either. Besides, from a manageability standpoint you don't want your implementation class(es) too large. One idea is the Strategy design pattern. Come "write" time, an instance of a Resume implementation class is supplied a ResumeWriteStrategy. After all, it's the client code (presumably), not the Resume object, that selects the actual output format. ResumeWriteStrategy is an interface that defines the abstract write operations that have to be implemented for each format; concrete classes (like ResumePDFWriteStrategy) actually do the heavy lifting. Your Resume "write" method now gets a strategy when it's invoked, and as write works through its abstract layout, it delegates its real writing to the supplied strategy object. Let's call the Strategy approach Option A. Another option would be to have a top-level AbstractResume that does basic implementation of Resume (the abstract layout in "write", for example), and concrete resume classes for each output format that know how to do the specific format. This isn't inherently bad: in either approach you need to write a new "something" to handle a new output format, and in any case your client code should only know about Resumes. Lew keeps on mentioning interfaces as "types" - exposing any and all incarnations of "resumes" to client code as a Resume, where Resume is an interface, is an example of this. This is Option B. I'd dispute anyone who said that Option A was substantially better than Option B, or vice versa. The only hitch with Option B is that when you obtain an instance of Resume, you do actually decide the output format right then and there. Whereas with Option A you simply have a "resume" implementation class instance, that doesn't know from formats, and it's only when the client code decides to have the resume output itself that the decision needs to be made. Depending on system requirements this could drive a choice. Let's return to the Strategy option. You should see the difference here between your ResumeFileWriter and my ResumeWriteStrategy. Your classes that implement your "writeResume" may appear to be superficially similar to what my strategy classes do, but there is one major difference: in your design the resume is a dumb object. This equates to saying that Resume doesn't know about its logical structure. Well, sure it does. ** Layout vs Logical Structure ** Now, logical structure isn't actually layout either, so as promised I'll revisit this. We originally have the single "write" method knowing how to layout at the abstract level. It uses logical structure elements to do this. Resume (implementations) should be loaded with logical structure, describing all the data that goes into a CV in an OO kind of way. Now, there are really 2 output issues, not just one. There is layout, and then there is output format. With a single "write" method in Resume you've hardwired to one layout, and odds are you'd like to be flexible here too. As mentioned before, Resume might want to switch between skills-oriented layout and chronology-oriented layout, as an example. There are also *style* type layout decisions: formal vs informal, for example. One can safely assume that these are all client code decisions. Not only that, they can combine. You might have formal+skills, or formal+chronology, or informal+chronology. So how to handle this? Adding subclasses in Option B doesn't look appealing - InformalChronologyHtmlResume is very klunky. I wouldn't want a ResumeFormalSkillsPDFWriteStrategy either. :-) Ultimately more interfaces. Interfaces in Java are the only "mixin" we've got. Maybe we continue the strategy idea, and supply more of them when we call "write". ** Summary ** None of this is authoritative, and I don't even claim it's the best way to do things. It's my thought process today, and 2 weeks from now it might be slightly different. Usually what I do, well before I reach this point, is to code as I think design. Nobody needs the "last mile" code at this point, which is to write out the actual PDF or HTML into files or to some other stream; you're just playing with interfaces and stubbed implementation classes, and some simple client code. Think other design patterns too. I've called out just one, and it's not necessarily the only one or even the best one. There are a number of other structural and behavioural patterns that should be thought of, and examined, in this problem. This is actually an excellent problem for learning Java and OO, so leverage the hell out of it. :-) What I've set out here is one example of a train of thought. If you remember anything from this, it's in my first paragraph: avoid value objects that are weak in behaviour. Lots of Java code that you will encounter is actually very procedural, not really OO at all, so be careful about what you seize on as examples. AHS -- -- Gaiety is the most outstanding feature of the Soviet Union. Josef Stalin, November 1935
[toc] | [prev] | [next] | [standalone]
| From | Jeff Higgins <jeff@invalid.invalid> |
|---|---|
| Date | 2012-03-08 09:11 -0500 |
| Message-ID | <jjael9$qbc$1@dont-email.me> |
| In reply to | #12760 |
On 03/07/2012 07:27 PM, Novice wrote:
> This is actually a discussion ...
import java.io.Writer;
import java.util.Locale;
public interface Resume {
Writer write(Template t, Locale l);
}
public interface Template {
Element root();
}
// ElementVisitor ana Element
// swiped from javax.lang.model
public interface ElementVisitor<R, P> {
/**
* Visits an element.
* @param e the element to visit
* @param p a visitor-specified parameter
* @return a visitor-specified result
*/
R visit(Element e, P p);
}
import java.util.List;
import java.util.Locale;
public interface Element {
<R, P> R accept(ElementVisitor<R, P> v, P p);
AttributeSet attributes();
AttributeSet attributes(Locale l);
Element enclosingElement();
List<? extends Element> enclosedElements();
}
// AttributeSet
// swiped from javax.swing.text
public interface AttributeSet {
public int count();
public Object get(Object key);
public boolean contains(Object name, Object value);
public boolean containsAttributes(AttributeSet attributes);
public AttributeSet parent();
}
[toc] | [prev] | [next] | [standalone]
| From | Jeff Higgins <jeff@invalid.invalid> |
|---|---|
| Date | 2012-03-08 09:35 -0500 |
| Message-ID | <jjag32$2nj$1@dont-email.me> |
| In reply to | #12764 |
On 03/08/2012 09:11 AM, Jeff Higgins wrote:
> On 03/07/2012 07:27 PM, Novice wrote:
>> This is actually a discussion ...
>
> import java.io.Writer;
> import java.util.Locale;
> public interface Resume {
Writer write(Template t);
> Writer write(Template t, Locale l);
> }
>
> public interface Template {
> Element root();
> }
>
> // ElementVisitor ana Element
> // swiped from javax.lang.model
>
> public interface ElementVisitor<R, P> {
> /**
> * Visits an element.
> * @param e the element to visit
> * @param p a visitor-specified parameter
> * @return a visitor-specified result
> */
> R visit(Element e, P p);
> }
>
Oops. skip the AttributeSet, you can include it in the P parameter.
> import java.util.List;
> public interface Element {
> <R, P> R accept(ElementVisitor<R, P> v, P p);
> Element enclosingElement();
> List<? extends Element> enclosedElements();
> }
>
[toc] | [prev] | [next] | [standalone]
| From | Jeff Higgins <jeff@invalid.invalid> |
|---|---|
| Date | 2012-03-08 19:24 -0500 |
| Message-ID | <jjbiio$p8v$1@dont-email.me> |
| In reply to | #12765 |
On 03/08/2012 09:35 AM, Jeff Higgins wrote:
> On 03/08/2012 09:11 AM, Jeff Higgins wrote:
>> On 03/07/2012 07:27 PM, Novice wrote:
>>> This is actually a discussion ...
>>
>> import java.io.Writer;
>> import java.util.Locale;
>> public interface Resume {
Nah, skip all of that. I've decided to store my resume data in an
instance of Candidate[1] and my resume output style in a stylesheet and
transform via JAXP.
HR-XML Standards 3.2 Release
<http://www.hr-xml.org/>
[toc] | [prev] | [next] | [standalone]
| From | Jeff Higgins <jeff@invalid.invalid> |
|---|---|
| Date | 2012-03-08 19:36 -0500 |
| Message-ID | <jjbj84$t07$1@dont-email.me> |
| In reply to | #12784 |
On 03/08/2012 07:24 PM, Jeff Higgins wrote:
> On 03/08/2012 09:35 AM, Jeff Higgins wrote:
>> On 03/08/2012 09:11 AM, Jeff Higgins wrote:
>>> On 03/07/2012 07:27 PM, Novice wrote:
>>>> This is actually a discussion ...
>>>
>>> import java.io.Writer;
>>> import java.util.Locale;
>>> public interface Resume {
>
> Nah, skip all of that. I've decided to store my resume data in an
> instance of Candidate[1] and my resume output style in a stylesheet and
> transform via JAXP.
>
> HR-XML Standards 3.2 Release
> <http://www.hr-xml.org/>
If you hate XML as a data storage format or already have a bunch of data
in format X see:
<http://docs.oracle.com/javase/tutorial/jaxp/xslt/generatingXML.html>
[toc] | [prev] | [next] | [standalone]
| From | Novice <novice@example..com> |
|---|---|
| Date | 2012-03-11 23:29 +0000 |
| Message-ID | <XnsA013C63B02665jpnasty@94.75.214.39> |
| In reply to | #12760 |
Novice <novice@example..com> wrote in news:XnsA00FC7119110Ajpnasty@94.75.214.39: [snip] I think I need to put these questions aside for a bit and focus on more pressing programming needs, especially logging and error handling. In fact, that's pretty much what I HAVE been doing for the last several days ;-) I probably shouldn't have started this thread until I had a bit more time to devote to it. I have read the responses Arved and Jeff made so far and found them interesting and thought-provoking. But I don't have the time just now to really follow through properly on the theme of this discussion. I'll start another thread on design of interfaces when I have more time. Thanks to Jeff and Arved for their ideas! -- Novice
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.java.programmer
csiph-web