【问题标题】:Implementing the observer pattern in Java, same observer across multiple classes用Java实现观察者模式,跨多个类的同一个观察者
【发布时间】:2013-12-03 11:04:04
【问题描述】:

所以我正在修改一个现有的开源项目,我创建了一个新的监视器类,我用它来使用观察者模式观察现有类的变化,这本身正被更多的监视器类监视。

在原始系统的主类中,我已经让它工作了,但是当程序切换到其他类时,我试图通过新类的构造函数传递管理器(通过由接口管理器表示的传递包含程序更新监视器的 send() 函数。但是,当我尝试从另一个类调用 send 时,它不起作用(它在第一个类中,称为 Main)。

当我在这个新类中声明的“MouseHandler”类中调用 send() 时,出现以下错误:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at kabalpackage.GameArea$MouseHandler.mouseReleased(GameArea.java:565)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

我尝试在这个 MouseHandler 类中声明另一个 Manager 变量,并在构造函数中传递它,但得到了同样的错误。

这是它工作的类,但为了简单起见,我省略了很多代码。

/*added necessary imports */
import java.util.*;
import monitors.Manager;
import monitors.MonManager;


 public class Main
 extends JFrame
 {
//  added manager variable
public static Manager manager;

public Main(Manager m)
{
     // this is where I set the manager provided in the constructor
             this.manager = m;

    // ..... lots of code skipped

    //  I try and pass the manager in to the new class here
private GameArea gameArea = new GameArea(manager);

private class MenuBar
extends JMenuBar
{
    //.....lots of code skipped
    }

    private class MenuListener
    implements ActionListener
    {
        private MenuListener() {}

        public void actionPerformed(ActionEvent e)
        {
            String event = e.getActionCommand();
            if (event.equals("New Game"))
            {


                // here is where i call send on the monitor
                                    System.out.println("Sending win 0"); 
                manager.send("win 0");
                Main.this.gameArea.newGame();
                System.out.println("New game");

                    }
                }
            }
        }
    }
}

如您所见,在类中声明了一个新类。这是从上述类调用的类 GameArea,如您所见,我修改了构造函数以获取管理器(接口)对象,因此我可以将 SAME 监视器管理器传递给下一个类。我再次从这个类中省略了很多代码,包括一些导入(它仍然有 import java.util.*; 我相信它是发送事件所必需的)。

import monitors.MonManager;
import monitors.Manager;

public class GameArea
extends JPanel
{
public static Manager manager;
    // loads of variables omitted //

// heres the constructor for the class, a manager is passed in and set to variable Manager
    public GameArea(Manager m)
{
    setLayout(null);
    setBackground(this.BACKGROUND_COLOR);
    setCursor(new Cursor(12));
    this.manager = m;

    loadImages();
}
    // more code omitted //
public void newGame()
{
    removeAll();
            // this creates the mouse handler class where i try to call manager.send
    MouseHandler mh = new MouseHandler();


}


    // more code omitted //

public class MouseHandler
extends MouseInputAdapter
{   
    // variables omitted

    private MouseHandler() {
    }

    public void mouseMoved(MouseEvent e)
    {
         //
    }

    public void mousePressed(MouseEvent e)
    {
        // omitted code //
    }    
    public void mouseDragged(MouseEvent e)
    {
        // omitted code //
    }

    public void mouseClicked(MouseEvent e)
    {
        // omitted code
    }

    public void mouseReleased(MouseEvent e)
    {
        // more omitted code
            if ((this.SRC_STACK instanceof DealtCardsStack)) {
                GameArea.this.moves.clear();
                // a call of manager
                System.out.println("Sending moves");
                manager.send("moves");
            } else {
                GameArea.this.moves.add(new Move(this.SRC_STACK, this.DST_STACK, this.TMP_LIST));
                // Here is the call for the manager, which creates an error.
                System.out.println("Sending moves");
                manager.send("moves");
            }
        }
        else
        {
            this.SRC_STACK.showCards(this.TMP_LIST);
        }
    // skipped some code//
}

}

最后是我的管理器界面中的代码,由监视器管理器实现:

package monitors;

public interface Manager {

    public void send(String message);
} 

抱歉,如果问题不清楚。有很多代码要省略,所以看起来很乱,但我认为我遗漏的任何内容都不会对错误产生影响。所以基本上在 Main 类中,我的消息被发送到监视器实现 Manager,但在另一个类中它们不是,我不知道为什么。

非常感谢任何有耐心阅读的人,如果你能说出我的问题,特别感谢!

【问题讨论】:

  • 为什么managerGameArea 中是静态的?根据您向我们展示的代码,它看起来应该是一个实例成员。
  • 我的猜测:这行private GameArea gameArea = new GameArea(manager); 为 GameArea 提供了一个空管理器,因为此时 Main 构造函数尚未执行。只需将private GameArea gameArea; 放入类中,将gameArea = new GameArea(manager); 放入Main 构造函数中。
  • DSquare - 非常感谢,它已排序。我不会发现这么多年!如果你想把它作为答案,我可以给你一个赞成/打勾。谢谢老哥!
  • ajb:我可能在静态区域错误或其他东西中得到了非静态变量。我认为将它设为静态是有意义的,因为我只会实例化一次。
  • 很高兴我能帮上忙。 NullPointerExceptions 通常是最容易找出的错误。您只需要确定哪个变量为 null 并跟踪它,直到找到将其分配给 null 的点。在这种情况下,一开始。

标签: java class events observer-pattern


【解决方案1】:

字段初始化在实际构造函数执行之前完成,所以行

private GameArea gameArea = new GameArea(manager);

正在传递一个未初始化的管理器,从而导致 NullPointerException。

只需将初始化放在构造函数中作为gameArea = new GameArea(manager); 即可解决问题。

【讨论】:

    猜你喜欢
    • 2013-03-05
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多