Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Program Flow and OOP

Tags:

java

oop

I'm a Java newbie, and also new to OOP. I have been a procedural programmer for years, but now trying to learn OOP. I am trying to write a basic program for practice as I go through an online Java course. It's a program to track people's score for games. Here's what I'd like to happen:
1. Ask user for the number of players.
2. Ask for the names of the players.
3. Display the main program window for tracking score.

I am using Swing. My code currently displays a JTextField for #1 above. My thoughts were that I'd put an ActionListenter on the JTextField which would get/store the number of players when the user hits enter. This works. But the next steps are where I'm having problems with the OOP. Here is the code for my ActionListener:

private class InputHandler implements ActionListener
{
    public void actionPerformed(ActionEvent e)
    {
        String enteredText = e.getActionCommand();
        numPlayers = Integer.parseInt(enteredText.trim());
    }
}

Since I need the program to wait until I have numPlayers, I decided to instantiate the class to get the player names inside of that ActionListener. However, since this class is an ActionListener, there are restrictions on what I can/can't do in there. The class I want to instantiate is called GetPlayerNames, and it's just a public class that extends JFrame. I have tried putting this into actionPerformed (within InputHandler):

GetPlayerNames temp = new GetPlayerNames(numPlayers);

(I used "temp" here because I don't need to do anything with this variable...it's just the only way I could get it to work), but of course this gives a compiler warning because "temp" is never used. And of course, it's messy and bad form. Help?

like image 548
Jake Munson Avatar asked Nov 06 '22 02:11

Jake Munson


1 Answers

Also, because your ActionListener is a nested class, it can call methods in its parent class:

public class Game {

    private void initUI() {
        // ...
        textField.addActionListener(new InputHandler());
        // ...
    }

    // ...

    private void showPlayerNameFrame(int numPlayers) {
        GetPlayerNames playerNameFrame = new GetPlayerNames(numPlayers);
        playerNameFrame.setVisible(true);
    }

    // ...

    private class InputHandler implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String enteredText = e.getActionCommand();
            int numPlayers = Integer.parseInt(enteredText.trim());
            showPlayerNameFrame(numPlayers);
        }
    }
}

This can make your code clearer because the objects which 'own' the logic (in this case the Game class) are the ones performing the actual actions.

Usually it makes sense for the action listeners to only parse the action and pass off the handling to the class. This is because often many types of listeners may trigger the same event (e.g value change listeners, action listeners, mouse listeners)

Instead of an inner class, one can also use an anonymous class:

public class Game {

    private void initUI() {
        // ...
        textField.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String enteredText = e.getActionCommand();
                int numPlayers = Integer.parseInt(enteredText.trim());
                showPlayerNameFrame(numPlayers);
            }
        });
        // ...
    }

    // ...

    private void showPlayerNameFrame(int numPlayers) {
        GetPlayerNames playerNameFrame = new GetPlayerNames(numPlayers);
        playerNameFrame.setVisible(true);
    }

    // ...
}

With Java 8, you can also use a Lambda or a Method Reference instead of an anonymous class to achieve the same.

Lambda:

public class Game {

    private void initUI() {
        // ...
        textField.addActionListener(e -> {
            String enteredText = e.getActionCommand();
            int numPlayers = Integer.parseInt(enteredText.trim());
            showPlayerNameFrame(numPlayers);
        });
        // ...
    }

    // ...

    private void showPlayerNameFrame(int numPlayers) {
        GetPlayerNames playerNameFrame = new GetPlayerNames(numPlayers);
        playerNameFrame.setVisible(true);
    }

    // ...
}

Method Reference:

public class Game {

    private void initUI() {
        // ...
        textField.addActionListener(this::showPlayerNameFrame);
        // ...
    }

    // ...

    private void showPlayerNameFrame(ActionEvent e) {
        String enteredText = e.getActionCommand();
        int numPlayers = Integer.parseInt(enteredText.trim());
        showPlayerNameFrame(numPlayers);
    }

    private void showPlayerNameFrame(int numPlayers) {
        GetPlayerNames playerNameFrame = new GetPlayerNames(numPlayers);
        playerNameFrame.setVisible(true);
    }

    // ...
}

In most cases, Method References are probably the best way to implement ActionListeners in terms of maintainability and readability of source code.

like image 94
jimmycavnz Avatar answered Nov 15 '22 01:11

jimmycavnz