is this a design problem?

Discussion in 'Java' started by gerrymcc@indigo.ie, Aug 20, 2003.

  1. Guest

    Hello, I hope it's okay to post to the three groups simultaneously.
    I've got a set of four applets, all of which use the same GUI,
    except for one change. I want to reuse the 100+ lines of setup code
    for the GUI, but can't seem to do that because of the single line that

    changes. Cutting and pasting the redundant code works, but it's a
    pretty dull solution.
    The idea of the following is that I have an Answer class (subclass of
    Panel) called studentWork. studentWork contains an array of
    EditableMeasure types (which are Canvas subclasses). In applet Two I
    have a mix of EditableMeasures and EditableMeasureTypeTwos, in applet
    Three I have a mix of EditableMeasures and EditableMeasureTypeThrees,
    etc. This is the only change to the GUI, and have had to make the
    single change in init() each time - studentWork = new Answer(this,
    selectedMode); or studentWork = new AnswerType2(this, selectedMode);
    or new AnswerType3( etc). The code below doesn't work, I guess
    because the call to super.init() must use the setStudentWork() from
    class One, rather than the definition I want, in class Two.
    Is there any way the code from init() and itemStateChanged can be
    reused and still create the relevant type of studentWork?

    Thanks for any help,
    Gerard

    import java.awt.event.*;
    import java.awt.*;
    import java.applet.*;

    public class One extends Applet implements ActionListener,
    ItemListener{

    Answer studentWork;
    Panel workArea;
    int [] selectedMode;

    public void init() {
    setStudentWork();
    // 100+ lines of gui setup follows
    workArea = new Panel();
    workArea.add( studentWork);
    }

    void setStudentWork(){
    studentWork = new Answer( this, selectedMode);
    }

    public void itemStateChanged( ItemEvent ie){
    switch( modeChoice.getSelectedIndex()){
    case 0: selectedMode = aChoice;
    break;
    . ...
    }
    setStudentWork();
    workArea.add(studentWork);
    }

    public void actionPerformed( ActionEvent e){...}
    }

    class EditableMeasure extends Canvas implements MouseListener,
    MouseMotionListener{
    // hundreds of lines
    }

    class Answer extends Panel{
    public EditableMeasure [] bar;

    public Answer() {}
    public Answer(One a, int [] part){
    setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    bar = new EditableMeasure[ part.length];
    for( int i = 0; i<part.length; i++){
    if( i == 0)
    bar = new EditableMeasure( a, 1);
    else if( i == part.length - 1)
    bar = new EditableMeasure( a, 2);
    else
    bar = new EditableMeasure( a);

    add( bar);
    }
    }
    }

    class Two extends One{
    public void init(){
    super.init();
    }
    void setStudentWork(){
    studentWork = new AnswerType2( this, selectedMode);
    }
    }

    class EditableMeasureType2 extends Canvas etc{}

    class AnswerType2 extends Answer{
    public AnswerType2 (Two a, int [] part){
    setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    bar = new EditableMeasure[ part.length];
    for( int i = 0; i<part.length; i++){
    if( i == 0)
    bar = new EditableMeasureType2( a, 1);
    else if( i == part.length - 1)
    bar = new EditableMeasure( a, 2);
    else
    bar = new EditableMeasureType2( a);
    add( bar);
    }
    }
    }
    , Aug 20, 2003
    #1
    1. Advertising

  2. wrote:
    > Hello, I hope it's okay to post to the three groups simultaneously.


    No, not really. [CLJ removed because it doesn't exist; followups
    directed to CLJP.]

    > I've got a set of four applets, all of which use the same GUI,
    > except for one change. I want to reuse the 100+ lines of setup code
    > for the GUI, but can't seem to do that because of the single line that
    >
    > changes. Cutting and pasting the redundant code works, but it's a
    > pretty dull solution.


    You seem to be on the right track with your code below. It should not
    be necessary to implement a copy & paste solution, and such a thing will
    greatly increase your maintenance burden (if this is code you will need
    to maintain).

    > The idea of the following is that I have an Answer class (subclass of
    > Panel) called studentWork.


    Being a bit pedantic here, no, that's not what you have. You have a
    reference-type variable named studentWork that can hold a reference to
    an Answer.

    > studentWork contains an array of
    > EditableMeasure types (which are Canvas subclasses). In applet Two I
    > have a mix of EditableMeasures and EditableMeasureTypeTwos, in applet
    > Three I have a mix of EditableMeasures and EditableMeasureTypeThrees,
    > etc.


    Continuing with the pedantry, in different applets studentWork contains
    references to objects of different subclasses of Answer, or of class
    Answer itself. This is perfectly acceptable, and the details of the
    differences between the various classes are immaterial.

    > This is the only change to the GUI, and have had to make the
    > single change in init() each time - studentWork = new Answer(this,
    > selectedMode); or studentWork = new AnswerType2(this, selectedMode);
    > or new AnswerType3( etc). The code below doesn't work, I guess
    > because the call to super.init() must use the setStudentWork() from
    > class One, rather than the definition I want, in class Two.


    What do you mean it "doesn't work." Do you get a compile-time error?
    Does it compile and run but not do what you expect?

    I very much doubt whether the invocation by Two.init() of its
    super.init() causes any kind of runtime problem, but if that's all that
    Two.init() needs to do then it is better to just let Two inherit its
    superclass' init() method.

    There is some chance that you are running into problems related to these
    applets' packages -- you would be well advised to assign them and their
    associated classes to a package other than the default package. (The
    way the example code is written, One and Two will need to be in the same
    package.)

    It is also possible that you are running into problems related to the
    physical packaging of the classes. The classloader that loads Two will
    need to also be able to load One, which probably means that both classes
    should be in the same jar or in the same directory.

    > Is there any way the code from init() and itemStateChanged can be
    > reused and still create the relevant type of studentWork?


    As I said before, you appear to be going about it in a reasonable way.
    We can be more help to you if you give us the details of the actual
    problems you are experiencing.


    John Bollinger


    > import java.awt.event.*;
    > import java.awt.*;
    > import java.applet.*;
    >
    > public class One extends Applet implements ActionListener,
    > ItemListener{
    >
    > Answer studentWork;
    > Panel workArea;
    > int [] selectedMode;
    >
    > public void init() {
    > setStudentWork();
    > // 100+ lines of gui setup follows
    > workArea = new Panel();
    > workArea.add( studentWork);
    > }
    >
    > void setStudentWork(){
    > studentWork = new Answer( this, selectedMode);
    > }
    >
    > public void itemStateChanged( ItemEvent ie){
    > switch( modeChoice.getSelectedIndex()){
    > case 0: selectedMode = aChoice;
    > break;
    > ...
    > }
    > setStudentWork();
    > workArea.add(studentWork);
    > }
    >
    > public void actionPerformed( ActionEvent e){...}
    > }
    >
    > class EditableMeasure extends Canvas implements MouseListener,
    > MouseMotionListener{
    > // hundreds of lines
    > }
    >
    > class Answer extends Panel{
    > public EditableMeasure [] bar;
    >
    > public Answer() {}
    > public Answer(One a, int [] part){
    > setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    > bar = new EditableMeasure[ part.length];
    > for( int i = 0; i<part.length; i++){
    > if( i == 0)
    > bar = new EditableMeasure( a, 1);
    > else if( i == part.length - 1)
    > bar = new EditableMeasure( a, 2);
    > else
    > bar = new EditableMeasure( a);
    >
    > add( bar);
    > }
    > }
    > }
    >
    > class Two extends One{
    > public void init(){
    > super.init();
    > }
    > void setStudentWork(){
    > studentWork = new AnswerType2( this, selectedMode);
    > }
    > }
    >
    > class EditableMeasureType2 extends Canvas etc{}
    >
    > class AnswerType2 extends Answer{
    > public AnswerType2 (Two a, int [] part){
    > setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    > bar = new EditableMeasure[ part.length];
    > for( int i = 0; i<part.length; i++){
    > if( i == 0)
    > bar = new EditableMeasureType2( a, 1);
    > else if( i == part.length - 1)
    > bar = new EditableMeasure( a, 2);
    > else
    > bar = new EditableMeasureType2( a);
    > add( bar);
    > }
    > }
    > }
    >
    >
    John C. Bollinger, Aug 20, 2003
    #2
    1. Advertising

  3. Harald Hein Guest

    "" wrote:

    > Hello, I hope it's okay to post to the three groups
    > simultaneously.


    One would have been enough.

    > I've got a set of four applets, all of which use
    > the same GUI, except for one change. I want to reuse the 100+
    > lines of setup code for the GUI, but can't seem to do that because
    > of the single line that
    >
    > changes.


    A common structure to solve such problems looks like this:

    class Base {
    public void method() {
    // Do first part of common code here

    // For specific parts that have to be different
    // call a method
    result = special(arguments);

    // Continue with the common code
    }


    // Provide a default implementation for the special
    // method. Either leave it empty, or implement the
    // most common behavior.
    protected someResultClass special(arguments) {
    // do the most common thing
    return aResult;
    }
    }

    // Implement a subclass for the behavior that deviates
    // from the common behavior. All you have to do is to
    // override the special() method
    class Derived extends Base {
    protected someResultClass special(argument) {
    // do something different here
    return anotherResult;
    }
    }


    If you need the normal behavior use the base class:

    Base c = new Base();

    If you need the special behavior use something like

    Base c = new Derived();

    instead. Note that Base is used as the type for the varible in both
    cases. This allows client code to work independent of the actual
    version of special() that is used.

    If you need even more different versions, implement more subclasses of
    Base.
    Harald Hein, Aug 20, 2003
    #3
  4. Douwe Guest

    wrote in message news:<iNK0b.28299$>...
    > Hello, I hope it's okay to post to the three groups simultaneously.
    > I've got a set of four applets, all of which use the same GUI,
    > except for one change. I want to reuse the 100+ lines of setup code
    > for the GUI, but can't seem to do that because of the single line that
    >
    > changes. Cutting and pasting the redundant code works, but it's a
    > pretty dull solution.
    > The idea of the following is that I have an Answer class (subclass of
    > Panel) called studentWork. studentWork contains an array of
    > EditableMeasure types (which are Canvas subclasses). In applet Two I
    > have a mix of EditableMeasures and EditableMeasureTypeTwos, in applet
    > Three I have a mix of EditableMeasures and EditableMeasureTypeThrees,
    > etc. This is the only change to the GUI, and have had to make the
    > single change in init() each time - studentWork = new Answer(this,
    > selectedMode); or studentWork = new AnswerType2(this, selectedMode);
    > or new AnswerType3( etc). The code below doesn't work, I guess
    > because the call to super.init() must use the setStudentWork() from
    > class One, rather than the definition I want, in class Two.
    > Is there any way the code from init() and itemStateChanged can be
    > reused and still create the relevant type of studentWork?
    >
    > Thanks for any help,
    > Gerard
    >
    > import java.awt.event.*;
    > import java.awt.*;
    > import java.applet.*;
    >
    > public class One extends Applet implements ActionListener,
    > ItemListener{
    >
    > Answer studentWork;
    > Panel workArea;
    > int [] selectedMode;
    >
    > public void init() {
    > setStudentWork();
    > // 100+ lines of gui setup follows
    > workArea = new Panel();
    > workArea.add( studentWork);
    > }
    >
    > void setStudentWork(){
    > studentWork = new Answer( this, selectedMode);
    > }
    >
    > public void itemStateChanged( ItemEvent ie){
    > switch( modeChoice.getSelectedIndex()){
    > case 0: selectedMode = aChoice;
    > break;
    > . ...
    > }
    > setStudentWork();
    > workArea.add(studentWork);
    > }
    >
    > public void actionPerformed( ActionEvent e){...}
    > }
    >
    > class EditableMeasure extends Canvas implements MouseListener,
    > MouseMotionListener{


    > // hundreds of lines
    > }
    >
    > class Answer extends Panel{
    > public EditableMeasure [] bar;
    >
    > public Answer() {}
    > public Answer(One a, int [] part){
    > setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    > bar = new EditableMeasure[ part.length];
    > for( int i = 0; i<part.length; i++){
    > if( i == 0)
    > bar = new EditableMeasure( a, 1);
    > else if( i == part.length - 1)
    > bar = new EditableMeasure( a, 2);
    > else
    > bar = new EditableMeasure( a);
    >
    > add( bar);
    > }
    > }
    > }
    >
    > class Two extends One{
    > public void init(){
    > super.init();
    > }
    > void setStudentWork(){
    > studentWork = new AnswerType2( this, selectedMode);
    > }
    > }
    >
    > class EditableMeasureType2 extends Canvas etc{}
    >
    > class AnswerType2 extends Answer{
    > public AnswerType2 (Two a, int [] part){
    > setLayout( new FlowLayout( FlowLayout.LEFT,0,0));
    > bar = new EditableMeasure[ part.length];
    > for( int i = 0; i<part.length; i++){
    > if( i == 0)
    > bar = new EditableMeasureType2( a, 1);
    > else if( i == part.length - 1)
    > bar = new EditableMeasure( a, 2);
    > else
    > bar = new EditableMeasureType2( a);
    > add( bar);
    > }
    > }
    > }


    I don´t see any difference in the classes AnswerType2 and AnswerType
    accept that AnswerType uses one time the EditableMeasure instead of
    EditableMeasureType2. But I don´t see any differences in
    EditableMeasure and EditableMeasureType2. So in both cases keep it
    with one Class. Also the applets do not differ much. I´ve rewritten
    the code partialy .. I can probably increase the code its quality even
    more but for that I need the complete code. Note that
    createEditableMease returns just a canvas and that I have changed the
    first parameter of the constructor of Answer to Applet. I´ve also
    rewritten your bar[] array fill loop ... always try to move as much as
    possible code outside the loop since this increases performance (which
    in this case is not really a problem but anyway)

    Here is the code. I didn´t check it on typos :|

    import java.awt.event.*;
    import java.awt.*;
    import java.applet.*;

    public abstract class StudentApplet extends Applet implements
    ActionListener, ItemListener {

    Answer studentWork;
    Panel workArea;
    int [] selectedMode;

    public void init() {
    setStudentWork();
    // 100+ lines of gui setup follows
    workArea = new Panel();
    workArea.add( studentWork);
    }

    void abstract setStudentWork();

    public void itemStateChanged(ItemEvent ie){
    switch( modeChoice.getSelectedIndex()){
    case 0: selectedMode = aChoice;
    break;
    . ...
    }
    setStudentWork();
    workArea.add(studentWork);
    }

    public void actionPerformed( ActionEvent e){...}
    }

    public class One extends StudentApplet() {
    void setStudentWork() {
    studentWork = new AnswerType1(this, selectedMode);
    }
    }


    public class Two extends StudentApplet() {
    void setStudentWork() {
    studentWork = new AnswerType2(this, selectedMode);
    }
    }






    class abstract AbstractAnswer extends Panel {
    public EditableMeasure [] bar;

    public Answer() {}
    public Answer(Applet a, int part[]){
    setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
    bar = new EditableMeasure[part.length];

    int i = 0;
    bar = createEditableMease( a, 1);

    for(; i<part.length-1; i++){
    bar = createEditableMease( a, -1);
    }
    bar = createEditableMease( a, 2);
    }

    public Canvas createEditableMease(Applet a, int val) {
    Canvas result = createEditableMeaseImpl(a, val);
    add(result);
    return result;
    }

    public abstract Canvas createEditableMeaseImpl(Applet a, int val);

    }


    class AnswerType1 extends AbstractAnswer {
    public Canvas createEditableMeaseImpl(Applet a, int val) {
    if (val == -1)
    return new EditableMeasureType1(a);
    return new EditableMeasureType1(a, val);
    }

    }

    class AnswerType2 extends AbstractAnswer {
    public Canvas createEditableMeaseImpl(Applet a, int val) {
    if (val == -1)
    return new EditableMeasureType2(a);
    return new EditableMeasureType2(a, val);
    }

    }







    class EditableMeasureType1 extends Canvas implements MouseListener,
    MouseMotionListener {

    // hundreds of lines
    }

    class EditableMeasureType2 extends Canvas etc{}
    Douwe, Aug 24, 2003
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ZackS
    Replies:
    5
    Views:
    6,797
    Just an Illusion
    Jul 9, 2004
  2. SpamProof
    Replies:
    3
    Views:
    644
    SpamProof
    Dec 1, 2003
  3. dave
    Replies:
    5
    Views:
    589
    William Brogden
    Jul 17, 2004
  4. Tim Smith
    Replies:
    2
    Views:
    854
    Tim Smith
    Dec 15, 2004
  5. trint
    Replies:
    1
    Views:
    357
    trint
    Nov 21, 2006
Loading...

Share This Page