6
\$\begingroup\$

I'm writing an animal shelter program, which keeps a database of different classes of animals (dog, cat, monkey). Functions that create the form and add the animals are very similar (difference is two questions and the rest is the same). Is it possible to divide this functions into parts so that the program code is not repeated?

You can see the differences between the functions here at Diffchecker. They have a lot in common.

private void admitDog() {
    boolean lb = false;
    boolean nw = false;

    String[] options = {"OK"};
    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));

    JLabel nameLabel = new JLabel("What is his/her name?");
    JTextField nameField = new JTextField(10);
    panel.add(nameLabel);
    panel.add(nameField);

    JLabel favLabel = new JLabel("What is his/her favourite food?");
    JTextField favField = new JTextField(10);
    panel.add(favLabel);
    panel.add(favField);

    JLabel numTimesLabel = new JLabel("How many times is he/she fed a day?"); //tu tylko cyfry
    JTextField numTimesField = new JTextField(10);
    panel.add(numTimesLabel);
    panel.add(numTimesField);

    JLabel needWalkLabel = new JLabel("Does he need walk?");
    JRadioButton needWalkYes = new JRadioButton("Yes");
    JRadioButton needWalkNo = new JRadioButton("No");
    ButtonGroup needWalkGroup = new ButtonGroup();
    needWalkGroup.add(needWalkYes);
    needWalkGroup.add(needWalkNo);
    needWalkYes.setSelected(true);
    panel.add(needWalkLabel);
    panel.add(needWalkYes);
    panel.add(needWalkNo);

    JLabel likeBonesLabel = new JLabel("Does he like bones?");
    JRadioButton likeBonesYes = new JRadioButton("Yes");
    JRadioButton likeBonesNo = new JRadioButton("No");
    ButtonGroup likeBonesGroup = new ButtonGroup();
    likeBonesGroup.add(likeBonesYes);
    likeBonesGroup.add(likeBonesNo);
    likeBonesYes.setSelected(true);
    panel.add(likeBonesLabel);
    panel.add(likeBonesYes);
    panel.add(likeBonesNo);

    int selectedOption = JOptionPane.showOptionDialog(null, panel,
                "Enter informations", JOptionPane.NO_OPTION, JOptionPane.QUESTION_MESSAGE, 
                null, options , options[0]); //dODAMY jeszcze cancel

    if(selectedOption == 0)
    {
        String name = nameField.getText();
        String fav = favField.getText();
        int numTimes = Integer.parseInt(numTimesField.getText());
        if(likeBonesYes.isSelected())
                lb=true;
        if(needWalkYes.isSelected())
                nw=true;
        ArrayList<Owner> owners = getOwners();
        Dog newDog = new Dog(name, owners, lb, fav, numTimes, nw);
        kennel.addAnimal(newDog);
    }
}
private void admitCat() {
    boolean sr = false;
    String[] options = {"OK"};
    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));

    JLabel nameLabel = new JLabel("What is his/her name?");
    JTextField nameField = new JTextField(10);
    panel.add(nameLabel);
    panel.add(nameField);

    JLabel favLabel = new JLabel("What is his/her favourite food?");
    JTextField favField = new JTextField(10);
    panel.add(favLabel);
    panel.add(favField);

    JLabel numTimesLabel = new JLabel("How many times is he/she fed a day?"); //tu tylko cyfry
    JTextField numTimesField = new JTextField(10);
    panel.add(numTimesLabel);
    panel.add(numTimesField);

    JLabel shareRunLabel = new JLabel("Does he share run?");
    JRadioButton shareRunYes = new JRadioButton("Yes");
    JRadioButton shareRunNo = new JRadioButton("No");
    ButtonGroup shareRunGroup = new ButtonGroup();
    shareRunGroup.add(shareRunYes);
    shareRunGroup.add(shareRunNo);
    shareRunYes.setSelected(true);
    panel.add(shareRunLabel);
    panel.add(shareRunYes);
    panel.add(shareRunNo);

    int selectedOption = JOptionPane.showOptionDialog(null, panel,
                "Enter informations", JOptionPane.NO_OPTION, JOptionPane.QUESTION_MESSAGE, 
                null, options , options[0]); //dODAMY jeszcze cancel

    if(selectedOption == 0)
    {
        String name = nameField.getText();
        String fav = favField.getText();
        int numTimes = Integer.parseInt(numTimesField.getText());
        if(shareRunYes.isSelected())
                sr=true;
        ArrayList<Owner> owners = getOwners();
        Cat newCat = new Cat(name, owners, sr, fav, numTimes);
        kennel.addAnimal(newCat);
    }
}
\$\endgroup\$
  • \$\begingroup\$ Welcome to CodeReview! Awesome first question. \$\endgroup\$ – Legato Apr 5 '15 at 0:32
4
\$\begingroup\$

There are some abstractions that can be done here. I will try to walk you through it a bit.

Extracting methods

This pattern is something you do a lot:

JLabel xxx = new JLabel("???????????");
JTextField yyy = new JTextField(10);
panel.add(xxx);
panel.add(yyy);

This is a perfect opportunity to extract a method:

private JTextField inputField(JPanel panel, String prompt) {
    JLabel promptLabel = new JLabel(prompt);
    JTextField textField = new JTextField(10);
    panel.add(promptLabel);
    panel.add(textField);
    return textField;
}

Then whenever you need a text-prompt, use:

JTextField nameField = inputField(panel, "What is his/her name?");

Something similar can be done for Yes/No questions:

private JRadioButton yesNoField(JPanel panel, String prompt) {
    JLabel promptLabel = new JLabel(prompt);
    JRadioButton yes = new JRadioButton("Yes");
    JRadioButton no = new JRadioButton("No");
    ButtonGroup group = new ButtonGroup();
    needWalkGroup.add(yes);
    needWalkGroup.add(no);
    needWalkYes.setSelected(true);
    panel.add(promptLabel);
    panel.add(yes);
    panel.add(no);
    return yes;
}

Usage:

JRadioButton needWalkYes = yesNoField(panel, "Does he/she need walk?");

Additionally...

boolean lb = false;
boolean nw = false;

I had to look much further down in your code to see where/how these variables were used. The current names of these variables is not optimal. You might think that "the cool programmers" use short hard-to-understand variable names, but I'll tell you the truth: We do not. In this case likesBones and needsWalk would be much better names.

Additionally, to better see the usage of these variables, it is recommended to declare them as close to their usage as possible. Don't declare them at the top of your method. In fact, they are not needed at all. You can change the code that currently uses them.

if (selectedOption == 0) {
    String name = nameField.getText();
    String fav = favField.getText();
    int numTimes = Integer.parseInt(numTimesField.getText());
    ArrayList<Owner> owners = getOwners();
    Dog newDog = new Dog(name, owners, likeBonesYes.isSelected(),
       fav, numTimes, needWalkYes.isSelected());
    kennel.addAnimal(newDog);
}

Side note: Your Dog class seems to have an excessive amount of parameters to the constructor. This can be a code smell. Consider using setter methods instead, such as setNeedsWalk, setLikesBones, etc. or (advanced concept) use the Builder pattern.

It is possible to do more abstraction as well, but I think this should be good enough for now. You should be able to reduce your code size and code duplication a lot by using the inputField and yesNoField methods.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.