Как использовать ссылку на объект в качестве аргумента, если он создается после того, как класс принимает аргумент? - PullRequest
3 голосов
/ 13 сентября 2011

Итак, у меня есть этот код:

package com.erikbalen.game.rpg;
import com.erikbalen.platform.*;
import javax.swing.JFrame;

public class World extends Engine {

    public static void main(String[] args) {        

    Gui display = new Gui(/*takes a Player argument so i can get certain variables*/);
    display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    display.setSize(300,220);
    display.setVisible(true);

    Player player1 = new Dps("ebalen", display);
    Player player2 = new Healer("frankypanky", display);

    }

}

package com.erikbalen.game.rpg;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Gui extends JFrame implements ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = -384241835772507459L;
    private JLabel playerInfo;
    private JTextField textField;
    private final static String newline = "\n";
    private JTextArea feed;
    private JScrollPane scrollPane;
    private Player player;

    public Gui(Player currentPlayer) {
        super("Erik's RPG");
        this.player = currentPlayer;
        setLayout(new FlowLayout());

        playerInfo = new JLabel("<html>Health = " + currentPlayer.getHealth() + " | " + "Mana = " + currentPlayer.getMana() + "</html>");

        playerInfo.setBorder(BorderFactory.createTitledBorder(currentPlayer.getName()));

        textField = new JTextField(20);

        textField.addActionListener(this);

        feed = new JTextArea(5, 20);
        scrollPane = new JScrollPane(feed);
        feed.setEditable(false);

        add(playerInfo);
        add(feed);
        add(textField);
        add(scrollPane);

    }

    public void actionPerformed(ActionEvent textBox) {
         String text = textField.getText();
         this.player.chat(text);

    }

    public void printText(String text) {
        feed.append(text + "\n");
        feed.setCaretPosition(feed.getDocument().getLength());
    }

}

Моя проблема в том, что класс Gui принимает Player в качестве аргумента, а Player принимает Gui в качестве аргумента. Как я могу позволить обоим объектам воспринимать друг друга как аргументы? Не стесняйтесь сказать мне, если мой код неэффективен.

Ответы [ 3 ]

5 голосов
/ 13 сентября 2011

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

  • Создать графический интерфейс, создать игроков, передав графический интерфейс, затем добавить игроков в графический интерфейс.
  • Создайте игроков, создайте GUI, передав игроков, затем установите GUI для игроков
  • Создайте GUI в конструкторе игроков:

    Player(String name)
    {
        GUI gui = new GUi(this);
        ...
    }
    

Все они неидеальны:

  • Возможно, вы захотите, чтобы ваши классы были неизменными, что делает первые два варианта неприятными
  • Публикацияthis ссылка до того, как ваш конструктор завершит выполнение, имеет различные проблемы, как с точки зрения безопасности потока, так и модели памяти, а также потенциально позволяет конструктору GUI вызывать объект Player до его полной инициализации.

Это восходит к «попытка разорвать зависимость» - но если это действительно невозможно, я бы , вероятно, предпочел бы первый вариант, без васне знаю ничего другого.Имеет смысл иметь возможность добавлять игроков в игру - меньше смысла устанавливать GUI для игрока после факта, IMO.

1 голос
/ 13 сентября 2011

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

Есть еще решения, но они не очень красивые.Для элегантного способа вы должны переосмыслить свой дизайн.Нужен ли GUI плеер?Может быть, вы могли бы создать метод, чтобы установить игрока позже.Если это невозможно, вы также можете создать сеттер в плеере.Вы не сможете установить оба во время строительства.

1 голос
/ 13 сентября 2011

Попробуйте указать методы класса Gui для обновления того, что отображается для пользователя / пользователей.Сделайте так, чтобы управляющий код (например, main()) отвечал за обновление Gui правильной информацией о событиях.

Ни Gui, ни Player не должны принимать друг друга в качестве аргументов конструктора -Gui должен отвечать только за отображение информации, о которой ему сообщается, а Player должен быть только логическим представлением игровой фигуры.Управляемая событиями функциональность должна быть зарезервирована для направляющего кода.

...