Results 1 to 12 of 12
Like Tree1Likes
  • 1 Post By SurfMan

Thread: Refactoring decisions, can someone suggest a strategy?

  1. #1
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Refactoring decisions, can someone suggest a strategy?

    Right now I'm developing a Swing app which uses a JFrame and JPanels within it in a BorderLayout. North and South areas each have a couple of JPanels which hold collections of sliders, toolbars, and buttons.

    Along with all of the menu handing code and file handling code, the source for this main JFrame class is now about 40 printed pages of 11 point text. I find myself, especially on a laptop with a small display, spending way too much time scrolling around looking for what I'm working on.

    I tried extracting the JPanel class which holds 8 JButtons out to a separate class file which makes it easier to work on that JPanel's code. However, now that I'm decoupled from the JFrame code, I no longer have direct access to the variables of the JFrame which are used by the rest of the program.

    I am looking into creating an Observer Pattern event trigger/listener, so that the JFrame can register a listener to the JPanel and make changes to its variables when a button is clicked. That's a bit complicated but as it has general application to many areas of my program, it might be worth it to try with this simple example.

    I could also pass the Frame handle into the extended JPanel class when I create it, so that the panel could call the JFrame's setter/getter for the variable in question. That makes the solution less general purpose than the event listener approach, but it would probably work OK for the purposes of my program.

    All 3 of these approaches would probably "work":

    1. Keeping the JPanel code within the Frame class so it can access the Frame's variables directly, based on handling button events.
    2. Adding an event handler/listener within a separated class with only the JPanel in it. Then the Frame can listen for these and take action accordingly.
    3. Send the Frame as a parameter to the JPanel so that the JPanel can directly access setter/getter methods to change the Frame's variable.


    The last one doesn't sound right to me as I think I need this to be event driven. There's no particular point where I'm in a loop wondering whether a new button was clicked. I need to have that happen starting with a JButton event handler and then passing that one way or other to the Frame to do the appropriate thing.

    I'm wondering how others have handled this situation and what pluses and minuses of various approaches are. #1 seems the most straightforward but unfortunately I find it really hard to work this way because of all the code clutter (I'm using Eclipse Luna). #2 is easier to work on but adds code complexity. However I can leverage this approach in other areas of my code where I know it is really needed.

    Thanks for any suggestions!

    DL

  2. #2
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Refactoring decisions, can someone suggest a strategy?

    If you need to set unique variables in the main program then you can't really decouple anything. Because the JPanel instance will still need to get/set those specific variables. However, if those variables are general purpose and could be used in other applications, then why not define an interface of some basic getters and setters and have the class implement that interface. Then you can simply pass an instance of the frame to a method in the panel class which declares the interface type.

    Java Code:
    interface VarInterface {
       public void setWidth();
       public int getWidth();  // or whatever you need
    }
    class MyClass implements  VarInterface {
        JFrame frame = new JFrame();
        MyPanel panel = new MyPanel(this);
    }
    
    class MyPanel extends JPanel {
        VarInterface vi;
        public MyPanel(VarInterface vi) {
            this.vi = vi;
        }
        // use vi to set specific buttons
    }
    Regards,
    Jim
    Last edited by jim829; 10-09-2015 at 07:50 PM.
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  3. #3
    SurfMan's Avatar
    SurfMan is offline Godlike
    Join Date
    Nov 2012
    Location
    The Netherlands
    Posts
    1,991
    Rep Power
    8

    Default Re: Refactoring decisions, can someone suggest a strategy?

    An example of event driven is the PropertyChangeListener. It's readily available in classes that extends Component, so that bascially means all Swing classes support it. Here's an example that demonstrates it using PropertyChangeListeners:

    Java Code:
    package forum.propertychange;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    
    public class Demo extends JFrame {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    Demo demo = new Demo();
                    demo.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                    demo.setSize(400, 400);
                    demo.setVisible(true);
                }
            });
        }
    
        public Demo() {
            MyPanel myPanel = new MyPanel();
    
            //Make this JFrame listen to the MyPanelobject, using an inner class.
            myPanel.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if (evt.getPropertyName()
                           .equals("MyButton")) {
                        JOptionPane.showMessageDialog(Demo.this, evt.getNewValue(), "Event happened!", JOptionPane.INFORMATION_MESSAGE);
                    }
                }
            });
    
            getContentPane().add(myPanel);
        }
    }
    
    
    class MyPanel extends JPanel {
    
        public MyPanel() {
            setLayout(new FlowLayout());
    
            JButton button = new JButton(new AbstractAction("Click me!") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //Let MyPanel fire a property change event
                    MyPanel.this.firePropertyChange("MyButton", null, "clicked!");
                }
            });
    
            this.add(button);
        }
    
    }
    You could argue that you don't want to "abuse" the PropertyChange idiom for your own non-property events, but it's easily recreated without PropertyChange-classes. Here's an example using the more generic Java Swing Event classes/interfaces:

    Java Code:
    package forum.propertychange;
    
    import javax.swing.event.EventListenerList;
    import java.util.EventListener;
    
    public class OwnListener {
        //Generic list of listeners that implement EventListener
        private EventListenerList listeners;
    
        public OwnListener() {
            listeners = new EventListenerList();
        }
    
        public void addMyListener(MyListener listener) {
            listeners.add(MyListener.class, listener);
        }
    
        public void fireMyEvent() {
            MyListener[] listeners = this.listeners.getListeners(MyListener.class);
            for (MyListener listener : listeners) {
                listener.myEventHappened("This message is broadcasted!");
            }
        }
    }
    
    interface MyListener extends EventListener {
        void myEventHappened(String message);
    }
    "It's not fixed until you stop calling the problem weird and you understand what was wrong." - gimbal2 2013

  4. #4
    benji2505 is offline Senior Member
    Join Date
    Sep 2014
    Location
    MA, USA
    Posts
    398
    Rep Power
    6

    Default Re: Refactoring decisions, can someone suggest a strategy?

    If the GUI become too complex I usually have one class that sets up the graphics only and one class that handles all events. That usually takes care of the clutter and the added complexity is limited imho.

  5. #5
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Refactoring decisions, can someone suggest a strategy?

    Thanks a lot for the responses. As it turns out, the answer was right in front of my face for the past few years but I didn't pick up on it. Eclipse (using Luna at present) shows a little circle with "+" or "-" in it at the left edge starting at the beginning of each class declaration (and other things like imports). By selecting "-" for most of these, I've collapsed the display of all the things I don't currently care about down to one visible line. This took the printed length from about 40 pages down to 11. In fact it made it so I probably am not going to print it. Some things are just easier to work with if you print them, I've found. Usually it takes me about 3 minutes to figure out what I was trying to accomplish and then I throw it away.

    I backed out my change which made the panel class a separate file. It's now back in the main Frame class. Just too much extra logic that didn't really need to be there.

  6. #6
    SurfMan's Avatar
    SurfMan is offline Godlike
    Join Date
    Nov 2012
    Location
    The Netherlands
    Posts
    1,991
    Rep Power
    8

    Default Re: Refactoring decisions, can someone suggest a strategy?

    So, do I understand correctly, you folded/collapsed lines of code so it now makes sense? Trust me, if your class is 6000 lines, after folding your code, it's still 6000 lines. If the design is uncomprehensible spaghetti code, it still will be after folding it.

    Go ahead, stimulate your creativity and Java skills and make this an MVC-ish event driven thing. Imagine that the guy who will be maintaining this is a ruthless psychopath that knows where you live...
    jim829 likes this.
    "It's not fixed until you stop calling the problem weird and you understand what was wrong." - gimbal2 2013

  7. #7
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Refactoring decisions, can someone suggest a strategy?

    Quote Originally Posted by SurfMan View Post
    So, do I understand correctly, you folded/collapsed lines of code so it now makes sense? Trust me, if your class is 6000 lines, after folding your code, it's still 6000 lines. If the design is uncomprehensible spaghetti code, it still will be after folding it.

    Go ahead, stimulate your creativity and Java skills and make this an MVC-ish event driven thing. Imagine that the guy who will be maintaining this is a ruthless psychopath that knows where you live...
    The more general question in the case of a Swing app with multiple panels each holding dozens of controls is: is the "design" improved by separating those classes into individual files where they no longer can directly manipulate the variables of the parent frame? I generally separate things out into classes when I perceive that doing so would offer a more general purpose solution. However, in the case of this application, each panel is unique, and I'm not trying to make a general purpose component library. So even if I implemented event handlers and listeners, there would only ever be one listener for this panel. That seems to me to increase the code complexity and opportunity for bugs simply because I want to work on smaller files.

    My concession to anti-spaghetti is to group all functions associated with a given panel/class together where possible.

    As far as "is this truly an MVC design?", that's difficult for me to argue as I'm self taught in Java and probably do have some pretty bad habits.

    My main class displays all the menus, panels and the visual representation of the model. It also contains the most of the file functions, which I have similarly struggled to extract only to find that it didn't seem to make things easier to do so. The model itself is in a different class. And the code which handles mouse input which allows the user to adjust attributes of the model is indeed all event driven and in another class.

    The code has been open sourced for more than a year and as far as I can tell, only a couple of people have attempted to compile or extend it.

  8. #8
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Refactoring decisions, can someone suggest a strategy?

    You can always have inner or nested classes to help organize your code. The purpose of inner classes is to group classes together that are inter-related. In case you are not familiar with them, here is an example:

    Java Code:
    public class ClassStuff {
    
       private int value = 99;
       public static void main(String[] args) {
          new ClassStuff().start();
       }
       public void start() {
          InnerClass ic = new InnerClass(101);
          System.out.println(ic.innerValue);
          System.out.println(ic.getOuterValue());
          StaticInnerClass sic = new StaticInnerClass(888);
          System.out.println(sic.otherValue); // access private value
       }
    
       class InnerClass {
          private int innerValue;
          InnerClass(int v) {
             innerValue = v;
          }
          
          public int getOuterValue() {
             return value;
          }
       }
       
       static class StaticInnerClass {
          private int otherValue;
          StaticInnerClass(int val) {
             otherValue = val;
          }
          // Note: outer class instance fields are not accessible here because
          // this class is static.
       }
    }
    You should read more about these in the tutorials (see my signature).

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  9. #9
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Refactoring decisions, can someone suggest a strategy?

    Thanks Jim. In fact this is how I do it. It does not prevent the massive growth of a single source file though.

    Cheers,

    DL

  10. #10
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Refactoring decisions, can someone suggest a strategy?

    Well, going back to your original problem, some of the JDK API classes (or files) are 2400+ lines (e.g. HashMap). That does include comments and documentation. What you can do is refactor some of your classes to more general purpose classes (e.g. like the AbstractMap and Map interface which HashMap uses). Once those are defined and saved, you can forget about them. Your panel class could have an abstract ancestor which contains the basic stuff. Then you just extend it and add what you need. Also, I don't know what IDE you are using but in Eclipse you can set bookmarks to help navigate thru the code.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

  11. #11
    Digital Larry is offline Member
    Join Date
    Mar 2013
    Posts
    87
    Rep Power
    0

    Default Re: Refactoring decisions, can someone suggest a strategy?

    I'll tell you what I learned after a week or so.

    1) Printing out your code and looking at it for 30 minutes on the train is more effective than hours scanning up and down a page at a time on a laptop.

    2) This allowed me to easily see functional groups that could be pulled apart into separate classes. I had to go from direct manipulation of a handful of variables by nested classes to focussing on better organization of data into classes and getting these set by return values (e.g. from File Open methods).

    3) Taking all the file related functions to a separate class reduced the size of my main file by about 50%.

    4) I discovered that trying to serialize a nested class is a bad idea because it seems to include a copy of its parent class, which is definitely not what I wanted. So those classes, even though small, became individual files for easy serialization.

    5) After ripping it apart and putting it back together, it's still a bit of a mess. Think I'll have to print it out again and look at it on the train!

    Maybe I just haven't seen it discussed, but I'm looking for some tutorial of "best practices" for structuring Java Swing programs above a certain trivial size where it can all be one file. In my experience Java lets you do all sorts of ridiculously stupid things. I think I've probably done it 3 different ways in this one project just depending on how I was approaching things that week.

    Is there some sort of tool that can analyze a project's layout and structure?

  12. #12
    jim829 is offline Senior Member
    Join Date
    Jan 2013
    Location
    Northern Virginia, United States
    Posts
    6,226
    Rep Power
    13

    Default Re: Refactoring decisions, can someone suggest a strategy?

    Is there some sort of tool that can analyze a project's layout and structure?
    I don't know of a specific tool but there are tools that let you design oo programs using UML. Then you can supposedly generate the skeletal classes and methods and then use ad IDE to add the logic (some of these UML tools are IDE add-ons). And there are some UML tools that can also read in a set of Java files and generate the structure in UML. The last time I looked at these were over a year ago and were not free.

    Regards,
    Jim
    The JavaTM Tutorials | SSCCE | Java Naming Conventions
    Poor planning on your part does not constitute an emergency on my part

Similar Threads

  1. Please please need help with refactoring>>> urgent>>>
    By learningjava12 in forum New To Java
    Replies: 4
    Last Post: 12-15-2012, 03:30 PM
  2. Replies: 0
    Last Post: 07-30-2012, 04:11 AM
  3. Replies: 3
    Last Post: 01-11-2012, 01:25 PM
  4. Decisions.
    By whateverme in forum New To Java
    Replies: 2
    Last Post: 11-20-2010, 01:52 AM
  5. Refactoring
    By Nirmala102 in forum New To Java
    Replies: 3
    Last Post: 11-06-2009, 11:18 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •