Объектно-ориентированное программирование - вопрос о дизайне и доступ к соответствующим данным - PullRequest
2 голосов
/ 28 сентября 2011

Предположим, у вас есть следующий код в Timer: его главная цель - отсчитать секунды и показать их в графическом интерфейсе, который основан на Swing.Таймер является частью игры и используется для определения того, кто является победителем, путем выбора пользователя, который первым нашел решение.

Action updateClockAction = new AbstractAction() {

    public void actionPerformed(ActionEvent e) {

        JLabel secLabel = m_GameApplet.GetJpanelStartNetGame().GetJlabelSeconds();
        secLabel.setFont(new java.awt.Font("Lucida Handwriting", 1, 36));
        secLabel.setForeground(Color.red);
        secLabel.setText(Integer.toString(m_TimerSeconds));
        if (m_TimerSeconds > 0) {
            m_TimerSeconds--;
        } else if (m_TimerSeconds == 0) {
            m_Timer.stop();
            m_GameApplet.GetJpanelStartNetGame().GetJlabelSeconds().setText("0");
            m_GameApplet.GetJpanelStartNetGame().GetJbuttonFinish().setVisible(false);
            //Checking whether time ended for both players and no solution was recieved
            if (!m_WasGameDecisived) {
                System.out.println("Tie - No one had a solution in the given time");
            }
        }
    }
};
m_Timer  = new Timer(1000, updateClockAction);

Теперь у меня есть два основных пакета в реализации клиента A.GUI - удерживать все свинговые Jpanels и т. Д. B.LogicEngine

Теперь в LogicEngine у ​​меня есть класс, который называется GameManager, который должен управлять и хранить информацию об игре.

Моя текущая реализация вВ общем, это так: у меня есть JpanelMainGame, который находится в пакете GUI JpanelMainGame содержит JPanelGameBoard, который имеет ссылку (или, другими словами, содержит) экземпляр GameManger, который находится в другом пакете - LogicEngine package.

Итак, мои вопросы таковы:

  1. Где должен находиться весь приведенный выше код определения таймера?

    A.В JpanelMainGame?(JpanelMainGame должен иметь ссылку на него).

    B.В GameManger как часть данных игры

  2. В каждом решении, которое вы даете, как мне получить доступ ко всей информации метки из анонимного внутреннего класса?Поскольку я могу получить доступ только к члену из внешнего класса с помощью команды: OuterClass.this.member.

  3. Любые комментарии о текущем дизайне.

Спасибо большоемного

Ответы [ 2 ]

2 голосов
/ 28 сентября 2011

Я повторяю ответ, который я дал на другой вопрос :

Я настоятельно не рекомендую организовывать пакеты с точки зрения реализации, такие как контроллеры, данные и т. Д. Я предпочитаю группировать их по функциональности, то есть, feature1, feature2 и т. Д. Если функция достаточно сложна и требует большого количества классов, то (и только потом) я создаю подпакеты, как указано выше, то есть feature1.controllers, feature1.data и т. д.

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

Хорошо, чтобы не отвечать на вопросы вопросами, но ...

  • Как часто используется таймер?
  • Запрограммирован ли таймер для общего использования или для определенного класса?

Если таймер общего назначения, то я бы сказал, что он принадлежит где-то в дереве пакетов LogicEngine.Однако, если Timer можно использовать только в элементе GUI, он относится к дереву пакетов GUI.

Как общее правило (не стучать по Agile-барабану слишком сильно), вам следует только кодироватьчто имеет смысл сейчас но не бойтесь изменить его позже.

Пример: вы создаете анонимный внутренний класс типа AbstractAction () в вашем коде.Это прекрасно (хотя я уклоняюсь от аноновых классов), если переменная updateClockAction используется просто.Но как только ваше кодирование приводит вас к необходимости пересекать границы updateClockAction (через OuterClass.this.member), тогда я утверждаю, что пришло время немного реорганизовать: извлечь этот внутренний класс и сделать его полностью квалифицированным классом.Таким образом, вы можете надлежащим образом контролировать внутреннее состояние объекта updateClockAction (используя cstr, getter и т. Д.)

EDIT: добавлен запрошенный пример

public class Testing {
    private Timer timer; /* INIT this from somewhere.... */

    public void myFunction() {
    /* 60 Seconds */
    long countDownTimeSEC = 60; 
    /* convert to Miliseconds */
    long countDownTimeMS = 1000 * countDownTimeSEC; 

    /* Get ref to label */
    JLabel label = m_GameApplet.GetJpanelStartNetGame().GetJlabelSeconds(); 

    /* Set once */
    label.setFont(new java.awt.Font("Lucida Handwriting", 1, 36)); 
    label.setForeground(Color.red);

    /* Set initial time */
    label.setText(Long.toString(countDownTimeSEC)); 

    /* Get ref to button */
    JButton button = m_GameApplet.GetJpanelStartNetGame().GetJbuttonFinish(); 

    /* Set up post Count Down list */
    ArrayList<AbstractAction> actsWhenComplete = new ArrayList<AbstractAction>();

    /* instantiate countdown object */
    CountDownClockAction cdca = new CountDownClockAction(label, countDownTimeMS, actsWhenComplete);
    this.timer  = new Timer(1000, cdca);

    /* Now that we have a timer, add the post Count Down action(s) to the  post Count Down list */
    actsWhenComplete.add(new CountDownFinishAction(label, button, this.timer));


    /* Finally, kick off the timer */
    this.timer.start();
}

public static class CountDownClockAction extends AbstractAction {
    private static final long serialVersionUID = 1L;
    private final JLabel labelToUpdate;
    private final long startMS;
    private long currentMS;
    private long timeMark;
    private final ArrayList<AbstractAction> actionsToExeWhenComplete;
    private boolean actionsExedFlag;

    public CountDownClockAction(
            final JLabel labelToUpdate, 
            final long startMS, 
            ArrayList<AbstractAction> actionsToExeWhenComplete
    ) {
        super();
        this.labelToUpdate = labelToUpdate;
        this.startMS = startMS;
        this.currentMS = startMS;
        this.timeMark = 0;
        this.actionsExedFlag = false;
        this.actionsToExeWhenComplete = actionsToExeWhenComplete;
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        /* First time firing */
        if (this.timeMark == 0) 
            this.timeMark = System.currentTimeMillis();

        /* Although the Timer object was set to 1000ms intervals, 
         * the UpdateClockAction doesn't know this, nor should it
         * since > or < 1000ms intervals could happen to do the fact that
         * the JVM nor the OS have perfectly accurate timing, nor do they
         * have instantaneous code execution properties.
         * So, we should see what the *real* time diff is...
         */
        long timeDelta = System.currentTimeMillis() - this.timeMark;

        /* Allow for the label to be null */
        if (this.labelToUpdate != null)
            labelToUpdate.setText(Long.toString((long)(currentMS / 1000)));

        if (currentMS > 0) {
            currentMS -= timeDelta;

        } else if (currentMS <= 0 && this.actionsExedFlag == false) {
            /* Ensure actions only fired once */
            this.actionsExedFlag = true;
            /* Allow for the label to be null */            
            if (this.actionsToExeWhenComplete != null)
                for (AbstractAction aa: this.actionsToExeWhenComplete)
                aa.actionPerformed(e);
        }

        /* Finally, update timeMark for next calls */
        this.timeMark = System.currentTimeMillis();
    }
}

public static class CountDownFinishAction extends AbstractAction {
    private final JLabel labelToUpdate;
    private final JButton buttonToUpdate;
    private final Timer timerToStop;

    public CountDownFinishAction(
            JLabel labelToUpdate,
            JButton buttonToUpdate, 
            Timer timerToStop
    ) {
        super();
        this.labelToUpdate = labelToUpdate;
        this.buttonToUpdate = buttonToUpdate;
        this.timerToStop = timerToStop;
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        /* Perform actions, allowing for items to be null */
        if (this.labelToUpdate != null)
            this.labelToUpdate.setText("0");

        if (this.buttonToUpdate != null)
                this.buttonToUpdate.setVisible(false);

            if (this.timerToStop != null)
                this.timerToStop.stop();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...