面向对象编程 - 关于设计和访问相关数据的问题

时间:2011-09-28 16:24:54

标签: java oop swing user-interface timer

考虑一下Timer中有以下代码: 它的主要目标是倒数秒并在GUI上显示,这是基于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包。

所以我的问题是这些:

  1. 上面的所有计时器定义代码应该放在哪里?

    一个。在JpanelMainGame? (JpanelMainGame应该引用它)。

    B中。在GameManger中作为游戏数据的一部分

  2. 在您给出的每个解决方案中,我应该如何从匿名内部类中访问所有标签信息?因为我只能使用命令OuterClass.this.member来访问外部类的成员。

  3. 有关当前设计的任何评论。

  4. 非常感谢

2 个答案:

答案 0 :(得分:2)

我重复我在another question上给出的答案:

  

我强烈反对从实现的角度组织软件包,如控制器,数据等。我更喜欢按功能对它们进行分组,即feature1,feature2等。如果某个功能相当复杂且需要大量数据然后(并且只有那时)我创建上面的子包,即feature1.controllers,feature1.data等。

答案 1 :(得分:1)

不要回答有问题的问题,但是......

  • 定时器的使用频率是多少?
  • 定时器是编码为通用还是特定于某个类?

如果Timer是常用的,那么我会说它属于某个地方的LogicEngine包树。但是,如果Timer只能在GUI元素中使用,那么它属于GUI包树。

作为一般的经验法则(不要太敏锐地敲击敏捷鼓),你应该只编写现在有意义的,但不要害怕以后更改它。

示例:您正在代码中创建一个类型为AbstractAction()的匿名内部类。如果简单地使用updateClockAction变量,这很好(尽管我回避了异类)。但是一旦你的编码引导你需要跨越updateClockAction的边界(通过OuterClass.this.member),那么我断言它的时间进行一些重构:提取这个内部类并使它成为一个完全限定的类。这样,您就可以对updateClockAction对象的内部状态(使用cstr,getters等)进行适当的控制。

编辑:添加了请求的示例

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();
        }
    }
}