我一直在仔细阅读JMapViewer的开源代码。如果有人希望查看它,请检查SVN。
JMapViewer
简而言之,主要类是JMapViewer,这是a的扩展JPanel。还有一个非常重要的类称为DefaultMapController,它充当MouseListener主要类的。
DefaultMapController
MouseListener
我注意到的第一个奇怪的事情是查看器没有对控制器的引用。该JMapViewer构造器实例的一个匿名实例DefaultMapController,就像这样:
public JMapViewer() { // other stuff new DefaultMapController(this); }
在我看来,这是一个糟糕的设计选择,因为控制器具有大量的方法(选项,切换等-如下所示的示例),这些方法现在根本无法访问,那么它们有什么用?
public void setMovementMouseButton(int movementMouseButton) { // changes which mouse button is used to move the map }
控制器确实具有对观众的引用,如上面的第一个代码片段所示,这就是它能够执行控制的方式。
但是,后来我想到了更奇怪的东西!如果该侦听器的匿名实例没有引用,为什么还可以生存?GC是否应该迅速销毁它?还是GC足够聪明,以至于知道引用实时消息的侦听器类也JComponent必须保持实时状态才能正常工作,即使由于某种奇怪的原因而没有名称也是如此?
因此,有两个实际问题:
为什么GC不销毁对象? 这确实是一个糟糕的设计选择,还是我不知道有什么方法可以从实例化查看器的类中访问控制器?我想为这个开源库做出贡献,而我的第一个更改想法是更改JMapViewer该类以使其具有引用其控制器的字段,并更改构造函数以将当前匿名控制器分配给该新字段。但是,我想确保我不会无所遗漏。我已经在整个代码库中搜索了text DefaultMapController,并且它仅出现在其自己的类定义中以及JMapViewer构造函数中的匿名实例中。
编辑:
确实确实存在一种通过使用java.awt.Component方法访问匿名侦听器的方法getMouseListeners()。因此,从技术上讲,在我的应用程序中,我可以在此集合中搜索的实例DefaultMapController,并使用该实例访问更改控制器选项所需的方法。
java.awt.Component
getMouseListeners()
不过,要扮演魔鬼的拥护者,如果我坚持最初的想法,并给地图提供其控制器的参考,那么现在我有了一种循环参考(地图知道控制器,而控制器也知道地图)。这是一个坏主意吗?
抽象的父,JMapController拥有构造函数JMapViewer传递给它的引用DefaultMapController:
JMapController
public DefaultMapController(JMapViewer map) { super(map); }
附录:map由控制器保存的参考用于(有选择地)将最多三个控制器参考加到地图上EventListenerList,在此进行讨论。这些中的任何一个都将排除GC。至少一个有益的设计好处是,具体JMapController只需实现可用的接口。
EventListenerList
正如在此MVC大纲中所建议的那样,给视图提供对控制器的引用是不寻常的。与此相反,没有什么错,让控制器寄存器作为监听器的观点,所建议的在这里。
请注意,只有无参数JMapViewer构造函数会安装DefaultMapController。您可以使用替代构造函数,如的修订版29113中第57-59行的注释中所述Demo.java。这里检查一个完整的例子。