考虑一下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
包。
所以我的问题是这些:
上面的所有计时器定义代码应该放在哪里?
一个。在JpanelMainGame
? (JpanelMainGame
应该引用它)。
B中。在GameManger
中作为游戏数据的一部分
在您给出的每个解决方案中,我应该如何从匿名内部类中访问所有标签信息?因为我只能使用命令OuterClass.this.member
来访问外部类的成员。
有关当前设计的任何评论。
非常感谢
答案 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();
}
}
}