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

发布于 2024-12-07 01:22:14 字数 1896 浏览 1 评论 0原文

假设您在 Timer< 中有以下代码/代码>: 它的主要目标是倒计时并在基于 Swing 的 GUI 上显示它。 计时器是游戏的一部分,用于通过首先找到解决方案的用户来决定谁是获胜者。

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 的类,它应该管理和存储有关游戏的信息。

我当前的实现一般是这样的: 我有一个位于 GUI 包上的 JpanelMainGame JpanelMainGame 包含 JPanelGameBoard,它引用(或换句话说包含)GameManger 的实例,该实例位于不同的包 - LogicEngine 上 包。

所以我的问题是:

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

    A.在 JpanelMainGame 中? (JpanelMainGame 应该有对它的引用)。

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

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

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

非常感谢

Consider you have the following code in a Timer:
It's main goal is to count down the seconds and to show it on GUI, which is Swing based.
The Timer is part of the game and is used for a decision of who is the winner by taking the user who reached a solution first.

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

Now, I have two main packages in the client implementation
A.GUI - hold all the swing Jpanels etc.
B.LogicEngine

Now in LogicEngine I have a class that is called GameManager- that should manage and store information about the game.

My Current implementation in general is like this:
I have a JpanelMainGame which is on the GUI Package
JpanelMainGame contains JPanelGameBoard which has reference(or in other word contains) an instance of GameManger, which is on different package - The LogicEngine package.

So my questions are these:

  1. Where does all of the timer definition code above should be placed?

    A. In the JpanelMainGame? (JpanelMainGame should have a reference to it).

    B. In GameManger as a part of a data of the game

  2. In each solution you give, How should I access all the label info from within the anonymous inner class? As I can only access member from the outer class with command: OuterClass.this.member.

  3. Any comments about current design.

Thank you very much

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

放手` 2024-12-14 01:22:14

我重复我在另一个问题中给出的答案:

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

I repeat the answer I gave on another question:

I strongly discourage from organizing packages from an implementational point of view, like controllers, data, etc. I prefer grouping them by functionality, that is, feature1, feature2, etc. If a feature is reasonably complex and requires a large number of classes, then (and only then) I create subpackages like above, that is, feature1.controllers, feature1.data, etc.

巨坚强 2024-12-14 01:22:14

好吧,不是用问题来回答问题,但是……

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

如果计时器是通用的,那么我会说它属于 LogicEngine 包树中的某个位置。但是,如果 Timer 只能在 GUI 元素中使用,那么它属于 GUI 包树。

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

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

编辑:添加了请求的示例

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

Well not to answer questions with questions, but...

  • How often is Timer used?
  • Is Timer coded to be general use, or specific to a certain class?

If the Timer is general use, then I would say it belongs in the LogicEngine package tree somewhere. However, if Timer can only be used in a GUI element, then it belongs in the GUI package tree.

As a general rule of thumb (not to bang on the Agile drum too hard), you should only code what makes sense now but not be afraid to change it later.

Example: You are making an anonymous inner class of the type AbstractAction() in your code. This is just fine (although I shy away from anon classes) if the updateClockAction variable is used simply. But once your coding leads you to the need to cross the boundries of updateClockAction (via OuterClass.this.member) then I assert its time for a bit of refactoring: extract this inner class and make it a fully qualified class. This way, you can have the proper amount of control over the updateClockAction object's internal state (using the cstr, getters, etc)

EDIT: Added requested example

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文