views:

452

answers:

5

Hey everyone, I've been writing code in Java for awhile now, however I feel as though I lack in code "design" - that is, creating packages and separating classes and such. I'm just not sure when to create what.

So, I'm practicing :)

I am setting out to write a Calculator (with a Swing GUI), and I want to create a really good design for it.

So far, I have created a package with the following:

 com.kevin.Calculator
   > com
     > kevin
       > calculator
         > ui
           Swing_Calculator.java
         >utilities

I want to separate out the UI from the functionality (the math).

So far so good?

My Swing_Calculator.java is, right now, creating the GUI elements, as well as running the user interface. However, should I be "breaking down" the creation of the GUI elements into more classes? As I said earlier - I don't seem to know when it is best to do modularize. Here is my code so far:

 /**
 * 
 */
 package com.kevin.calculator.ui;

 import java.awt.Dimension;
 import java.awt.GridLayout;
 import java.awt.Panel;

 import javax.swing.*;

 /**
  * @author Kevin
  * 
  */
 public class Swing_Calculator {
/**
 * Creates the calculator's GUI and shows it on screen.
 */
private static void create_GUI() {
 // Create and set up the window.
 JFrame frame = new JFrame("KBehr's Kalculator");
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

 // Sets the size of the frame
 frame.setSize(300, 350);

 // Centers the frame on the screen
 // Should be called AFTER the frame size has been set
 frame.setLocationRelativeTo(null);

 // Creates a new Panel Object
 JPanel panel = new JPanel();

 // Sets the size of the panel
 panel.setPreferredSize(new Dimension(300, 350));

 // Creates a GridLayout object
 // http://java.sun.com/docs/books/tutorial/uiswing/layout/grid.html
 GridLayout button_grid = new GridLayout(0,3);

 // Adds the GridLayout to the Panel
 panel.setLayout(button_grid);

 // Adds the Panel to the Frame
 frame.getContentPane().add(panel);

 // Displays the window.
 frame.setVisible(true);
}

public static void main(String[] args) {
 // Schedule a job for the event-dispatching thread:
 // creating and showing this application's GUI.
 javax.swing.SwingUtilities.invokeLater(new Runnable() {
  public void run() {
   create_GUI();
  }
 });
}

 }

Can anyone offer some insight? Thanks!

+1  A: 

You should create a subclass of JFrame. In there you should set up your UI.

public class Kalculator extends JFrame {

    // buttons and stuff should be private member variables

    public Kalculator(){
        super("KBehr's Kalculator");
        // set up GUI here
    }
}

That is a basic class to get started with.

I usually make my ActionListeners private inner classes of the Frame.

Then inside the gui, on 'Equals' you will pass the arguments into the calculate method of your Math class.

That should provide a good start.

jjnguy
Thanks for your help!
behrk2
+4  A: 

GUI: For a simple GUI as a calculator what you have done would do; the only change I would probably make is move out the main method to a different class - "Application" or something.

Controllers and Logic: Next part is to seperate out the GUI handlers (the listeners); again this is not a strict rule; but it would definitely help on a bigger project. Even the listeners shouldn't have any core logic code. It should merely act as a bridge between the class(es) that implements the logic and your GUI. The implementation of the real logic (how to add, subtract etc in this case) should definitely be done in seperate classes/packages.

The advantage of doing this will not be very evident in such a small scale project, but when it is big; the real merits starts showing up.

What I described above is basically the Model-View-Controller architechture. Specific to Java there is this article at the Sun website. You would also find plenty of good books on these concepts too; pick up one, read and practise; that's the best way to do it I guess.

Rusty
Thanks for your guidance, I will definitely follow your suggestions, as well as check out the link you provided.
behrk2
+2  A: 

You could just write the application in a way that works, but make certain to include unit tests for your functions. Unit tests will help ensure that each method is relatively simple, otherwise the tests are too hard to write.

My basic thought is: 1. Make it work, which includes unit tests 2. Make it right, which is refactoring 3. Make it fast, which is profiling and optimizing.

I agree with Rusty that the MVC paradigm may work well for you, so you can try to break your application up this way.

Once you get it working, then you should read up on refactoring, as that will help you to decide how to change the structure.

There is a good book on Refactoring to Design Patterns that I liked.

Once you have written the application (step 1) then you may want to look at a book on Design Patterns, and see if there are patterns that you use to better organize your application. Design patterns make more sense once you have more experience writing, otherwise it becomes too easy to try to make patterns everywhere, even when it doesn't really make sense.

James Black
Thanks, I think it will also help that I'm taking a Design Patterns class this upcoming semester!
behrk2
Try to finish your calculator, and the class will make more sense. Unfortunately people seem to design to patterns rather than using them as a way to help with the design.
James Black
James, couldn't agree more. Don't fall into that trap early.
Rusty
+1  A: 

Packages - As the calculator's only going to have a few classes, you don't need to worry about design of packages too much, but as a rule of thumb, you want to minimise dependencies between them and have classes within them related around a central theme (low coupling, high cohesion). So, even a set of packages like com.kevin.calculator.view, com.kevin.calculator.controller and com.kevin.calculator.model are a good start.

Class Design - What you've started with is a pretty good attempt. When you go about deciding on classes, you should follow S.O.L.I.D design principles. In your case, the most important of these principles is the Single Responsibility Principle - ideally, every class should have only one reason to change. If it has more than one reason, coupling is increased, making improvements harder and unexpected side-effects more likely. For example, if you were to include the calculator (business) logic with the responsibility for updating the GUI, you'd have two reasons for change. In the future, you might want to add more calculator logic (think scientific calculator functions), or alternatively, change the appearance and positioning of the buttons. Having this all in the one class means we have to always be careful that changing one responsibility doesn't break the other. It also makes it harder for others to come and understand what's going on in the class. Model-View-Controller is a very nice and standard way of partitioning the responsibilities into separate classes, but even here, you want to make sure they contain only one reason to change, that's why it's common to have JTableModel type classes separate to JListModel classes.

Declarative Design - something else I found tremendously useful when I was starting out was making code as easy to read as possible by not using comments. Comments aren't bad, but question why you use them - is it because your code is hard-to-read? Much better than this is to use lots of methods with descriptive names. Instead of:

if(input < 0 || input > 999999999) {
   throw new BadInputException();
}
// continue processing

prefer

if (checkInputIsInvalid()) {
   throw new BadInputException();
}
// continue processing

because it tells the reader what you're doing, without getting them unnecessarily lost in the details of the code, when all they want to do is change a specific functionality (and may not even care about what's valid, only that a check is done).

shredderts
+1 That was exactly the answer I was waiting for. SOLID, Declarative Design and than you can remove most of the comments in the code. Great answer!
Andreas_D
+1  A: 

Since it is a simple application, play around with different "designs". The best designs are those that work! Once you're done, try refactoring it to make it a scientific calculator and see how painful or easy the changes are to make. These learned lessons are far more valuable than reading too many books or articles.

Yep, definitely designing in mind to expand it in the future. Thanks!
behrk2