Обработка неизвестного количества объектов в Java - PullRequest
0 голосов
/ 18 октября 2018

При программировании я часто сталкиваюсь с проблемой обработки неизвестного числа объектов.Под обработкой я подразумеваю ссылки на них, манипулирование ими и т. Д. Что касается меня, это будет при разработке небольших игр и программ.

В настоящее время я работаю над программой ведения счетов, в которой должны отображаться имена игроков, их оценки, а также различные другие функции.Кроме того, должно быть две кнопки, которые позволяют добавлять и удалять игроков из таблицы результатов, на чем я остановлюсь здесь.Это может выглядеть примерно так:

//A very limited version of my program
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class Application extends JFrame implements ActionListener{

    //Fields, variables and components
    Container mainCont = getContentPane();      //Main container, the window itself
    private JPanel buttonPanel;
    private JPanel namePanel;
    private JButton addPlayerButton;
    private JButton removePlayerButton;
    //...
    //Many more components

    public Application(){

        //Basic window initiation
        setTitle("Score Keeper");
        this.setSize(650, 700);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainCont.setBackground(Color.BLACK);
        this.setContentPane(mainCont);

        buttonPanel = new JPanel();
        namePanel = new JPanel();

        addPlayerButton = new JButton();
        addPlayerButton.addActionListener(this);
        buttonPanel.add(addPlayerButton);

        removePlayerButton = new JButton();
        removePlayerButton.addActionListener(this);
        buttonPanel.add(removePlayerButton);

        this.add(buttonPanel);
        this.add(namePanel);
        this.setVisible(true);

        //Other code omitted for now
        //Includes other graphic components, layout managers etc.

    }

    /*
    * Action-Listener. 
    * Performs an event on an action.
    */
    @Override
    public void actionPerformed(ActionEvent event){

        if(event.getSource() == addPlayerButton){
            Application.Player newPlayer = this.new Player();    //Creates a new object, i.e. a new player
            //See below for Player class
        }

        if(event.getSource() == removePlayerButton){
            //******
            // This is where the problem lies
        }

    }

    //I use a nested class to create a new player
    public class Player{

        //Components etc.

        private String name;
        private JLabel nameLabel;

        public Player(){

            name = getName();
            nameLabel = new JLabel(name);
            namePanel.add(nameLabel);


        }

        public String getName(){
            //This basically gets input from the user to assign a name to the new player
            //Code omitted for now

        }

    }

}

Пока все хорошо.Эта программа в основном имеет только две кнопки, где addPlayerButton добавляет объект проигрывателя, имя которого отображается на экране.Каждый раз, когда нажимается эта кнопка, новый игрок добавляется на экран.И это может быть сделано неограниченное количество раз.

Проблема возникает, когда мы хотим удалить игрока.Как мы можем сделать это?Мы не можем ссылаться на него по имени, так как все объекты игроков практически анонимны.

Альтернативой, конечно, было бы заранее определить фиксированное количество объектов игроков:

class Application extends JFrame implements ActionListener{

    //Fields, variables and components
    Container mainCont = getContentPane();      //Main container, the window itself
    private JPanel buttonPanel;
    private JPanel namePanel;
    private JButton addPlayerButton;
    private JButton removePlayerButton;

    private Player player1;
    private Player player2;
    private Player player3;
    //...
    //Etc.

Тогда мы сможем обратиться непосредственно к каждому объекту игрока, но это просто слишком непрактично.Мы не можем добавить больше игроков, чем заранее определенное количество, и если мы хотим меньше игроков, у нас есть куча объектов игроков, которые никогда не используются.Кроме того, мы должны были бы жестко закодировать каждое посвящение каждого игрока - каждый nameLabel должен был бы быть вручную добавлен на экран и т. Д.

Пожалуйста, поделитесь своими знаниями о том, как вы решаете проблемы такого рода, как вы справляетесь с ними.неизвестное количество объектов.Спасибо, что нашли время и за помощь!

PS Я все еще довольно новичок в этом форуме.Пожалуйста, дайте мне знать, если есть что-то с этим вопросом, который я могу изменить, и т. Д. Я провел исследование и не нашел ни одного предыдущего вопроса, который бы занимался этим, но если есть один, который я пропустил, не стесняйтесь, дайте мне знать!

РЕДАКТИРОВАТЬ 1: Хорошо.Было много отличных ответов.Я выбрал тот, который использовал hashmaps как правильное решение, так как считаю, что это лучшее решение для предоставленных мною помещений.То, как я на самом деле решил свою проблему, это то, что я добавил к объекту player JButton, который удаляет объект проигрывателя, в котором он хранится. Я также отказался от концепции использования вложенного класса для проигрывателя и просто реализовал его в отдельном классе.,Однако в целом я узнал, что при работе с объектами, а количество объектов вы не знаете, как правило, лучше хранить их в какой-то коллекции.Я предпочитаю Hashmap, так как он обеспечивает простой способ доступа к объекту на основе одного из его свойств, например, имени String или аналогичного.

Ответы [ 4 ]

0 голосов
/ 18 октября 2018

Предположим, что вы используете JList для отображения текущих игроков.Java Swing разделяет модель (где фактически отображаются отображаемые объекты) и вид и управление (JList, который их отображает).Этот дизайн называется MVC и является очень распространенным.

У нас есть разные способы хранения реальных Player объектов.Выбор зависит от того, как вы планируете манипулировать игроками.Наиболее простым является использование массива, но он работает только в том случае, если у вас никогда не будет слишком много игроков:

 Player[] players = new Player[MAX_PLAYERS](); // define MAX_PLAYERS somewhere
 int currentPlayers = 0;                       // always < MAX_PLAYERS

Чтобы выставить это на JList, вы должны использовать пользовательскую модель адаптера следующим образом (во внутреннем классе с доступом к массиву игроков):

 private final class PlayerListModel extends AbstractListModel<Player> {
     @Override
     Player getElementAt(int position) { return players[position]; }
     @Override
     int getSize() { return currentPlayers; }
 }

Затем вы можете передать это JList во время строительства:

 private PlayerListModel playerListModel = new PlayerListModel();
 private JList playersListView = new JList(playerListModel);

Теперь, чтобы удалить игрока по именисначала нужно обновить модель, а затем обновить представление:

 private void removePlayerByName(String name) {
     int toRemove = -1;
     for (int i=0; i<currentPlayers; i++) {
        Player p = players[i];
        if (p.getName().equals(name)) {
           toRemove = i;
           break;
        }
     }
     if (toRemove != -1) {
        // update model
        currentPlayers --; 
        players[toRemove] = players[currentPlayers];

        // update views
        playerListModel.fireContentsChanged(this, toRemove, currentPlayers);           
     }
 }

Вместо массива players было бы намного проще и безопаснее использовать ArrayList<Player> players.Однако, если вы называете свои переменные player1, player2 и так далее, я думаю, что вам следует начинать с массивов.Если вы хотите иметь более быстрый поиск игроков, то TreeMap<String, Player> позволит отсортировать их по имени и легко найти.В обоих случаях вам придется обновить модель и функцию removePlayerByName соответственно.Например, если использовать TreeMap, это будет намного короче (и быстрее):

 private void removePlayerByName(String name) {
    if (players.containsKey(name)) {
      players.remove(name);
      playerListModel.fireContentsChanged(this, 0, currentPlayers);           
    }
 }    

С другой стороны, гораздо чаще встречаются интерфейсы, где вы нажимаете на плеер, который выхотите удалить, чтобы выбрать его, а затем нажмите кнопку remove, чтобы фактически сделать это.Вы можете узнать, какой игрок был выбран с помощью этого кода:

Player selected = PlayersListView.getSelectedValue ();

Если есть выбор (selected != null), вы можете либо позвонить removePlayerByName(selected.getName()),или, что еще лучше, код removePlayer(Player p), который основывался не на именах, а на реализации (в настоящее время отсутствует) Player.equals(Player another).

0 голосов
/ 18 октября 2018

Вы можете использовать карту / хэш-карту и каждый раз, когда вы создаете игрока, добавлять их на карту.

Вы также должны перейти от прямого рисования игрока на экране, возможно, к рисованию всех игроковна карте, таким образом, когда игрок удаляется с карты, он больше не будет вытягиваться.

Вы бы сделали что-то вроде этого:

    Map<String, Player> map = new HashMap<>();
    map.put(player.Name, player);

И тогда вы бы нарисовали все вэто хэш-карта.Чтобы удалить, вам нужно просто указать имя игрока для удаления.

    map.remove(player.Name);

И, конечно, тогда вы немного изменили бы свой код, чтобы отобразить все внутри карты, я думаю, вам нужен способ узнатькакой игрок должен быть удален, вы можете добавить текстовое поле для ввода имени игрока, которого нужно удалить.

0 голосов
/ 18 октября 2018

Я бы @Katada Freije использовал метод HashMap.Просто чтобы уточнить, у вас в основном есть коллекция Players с их именами в качестве ключа.Затем вы используете ключ для удаления Player.

Но я мог бы также избежать этого, поскольку в некоторых сценариях есть несколько Players с одинаковыми именами.Я бы пошел с List<Player>.Таким образом, Player будет определяться индексом, а не именем.Затем вы использовали бы индекс, чтобы удалить игрока с некоторыми встроенными методами .

0 голосов
/ 18 октября 2018

Что вы можете сделать, если хотите удалить Player на основе его имени, следующее:

// Create a list of players, which you can define globally
ArrayList<Player> players = new ArrayList<>();

// The name of the player to find
String name = "theNameOfThePlayerToFind";

// Loop through the players and remove the player with the given name
for (Player player : players) {
    if (player.getName().equals(name)) {
        players.remove(player);
    }
}

Вы также можете легко добавлять новых игроков в списки:

players.add(new Player());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...