我正在尝试研究JavaFX,因为我想将它用作我程序的GUI。我的问题基本上是一个概念性问题:
到目前为止,我的程序主要是MVC模式的“模型”部分;也就是说,我的几乎所有代码都是类的意义上的抽象的OO表示,所有代码都是逻辑代码。
由于我不想成为我的程序的唯一用户,我想添加MVC的“View”部分,以便人们可以轻松地使用和操作我的程序的“模型”部分。为此,我想使用JavaFX。
在我的“Model”类中,我显然使用了Java Collections API中的各种Lists,Maps和其他类。为了让我的程序的用户操作这些底层列表和地图,我想在JavaFX中使用Observable(List / Map)接口。
澄清情况的具体例子:
假设我有一个 MachineMonitor 类,每3分钟检查一次机器的某些属性,例如连接是否仍然良好,齿轮转速等等。如果确定如果 MachineMonitor 触发RestartMachineEvent,则会遇到不等式(比如齿轮的速度下降到1转/秒)。
目前我使用的是ArrayList< MachineMonitor >跟踪所有单独的 MachineMonitor 。现在扩展到MVC的“View”部分,我希望User能够操作一个显示 MachineMonitor 列表的TableView,以便他们可以创建和删除新的 MachineMonitor 用于监控各种机器。
这样我就可以跟踪我的程序用户想要做什么(例如,为机器#5创建一个 MachineMonitor ,检查齿轮的转/秒是否低于0.5)我使用ObservableList< MachineMonitor >作为TableView的基础列表。
链接程序的“模型”和“视图”的最简单方法就是将“模型”类更改为具有ObservableList< MachineMonitor >而不是ArrayList< MachineMonitor >但是(谈到问题的主题)我觉得这非常混乱,因为它混合了“模型”和“查看”代码。
一种天真的方法是使用ObservableList< MachineMonitor >对于TableView并保留使用我的ArrayList< MachineMonitor >。但是,对ObservableList< MachineMonitor >所做的更改不要按照JavaFX规范影响基础List。
鉴于此,解决这个难题的最佳方法是为ObservableList< MachineMonitor >制作ChangeListener。 “传播”对ObservableList< MachineMonitor >所做的更改到底层的“模型”ArrayList< MachineMonitor >?也许把它放在一个名为MachineMonitorController的类中?
这种临时解决方案似乎非常混乱且不理想。
我的问题是:在这种情况下,保持“模型”和“视图”之间几乎完全分离的最佳方法是什么?
答案 0 :(得分:11)
简而言之,我并不认为使用ObservableList打破了MVC合约。
其余的,你可以读或不读,因为它非常烦人。
建筑图案背景
Observables在MVC样式体系结构中很有用,因为它们提供了一种通过松散耦合在MVC组件之间来回传递数据的方法,其中模型和视图类不需要直接相互引用,但可以使用一些传达数据流的共享数据模型。 Observable模式和MVC风格的架构概念在施乐帕洛阿尔托研究中心大致同时出现并不是巧合 - 事情是相互联系的。
如Martin Fowler's GUI architectures所述,构建GUI的方法有很多种。 MVC只是其中之一,是他们所有人的祖父。很好地理解MVC(经常被误解)并且MVC概念适用于许多地方。对于您的应用程序,您应该使用最适合您的系统,而不是严格遵循给定的模式(除非您使用强制执行给定模式的特定框架),并且还愿意在应用程序中采用不同的模式而不是尝试鞋拔一切都变成了一个概念框架。
Java Bean是几乎所有Java程序的基础部分。虽然传统上通常只在客户端应用程序中使用,但观察者模式(PropertyChangeListeners
)自创建以来一直是Java Bean specification的一部分。 JavaFX的可观察和绑定元素是对早期工作的重做,从中学习构建更方便使用和更容易理解的东西。也许,如果JavaFX可观察和绑定元素在十年或十二年前作为JDK的一部分存在,那么这些概念将比一些纯GUI框架更广泛地用于更广泛的库和框架中。
<强>建议强>
我建议考虑MVVM model和其他GUI架构。
如果你想要一个遵循模型,视图,演示者风格的简单框架,肯定会给afterburner.fx一个旋转。
我认为正确的架构选择取决于您的应用程序,您的体验以及您尝试解决的问题的大小和复杂性。例如,如果您有分布式系统,那么您可以遵循REST principles而不是(或除了)MVC。无论您选择哪种,架构都应该帮助您解决手头的问题(以及可能未来的问题)而不是相反的问题。过度构建解决方案是一个常见的陷阱,并且很容易做到,所以尽量避免使用它。
<强>买者强>
需要考虑的一点需要注意的是,可观察者必然会通过副作用起作用,这种副作用难以推理,并且可能与隔离概念相对立。 JavaFX提供了一些很好的工具,例如ReadOnlyObjectWrapper和ReadOnlyListWrapper,以帮助限制对可观察对象的影响(如果您愿意,可以进行损坏控制),这样他们就不会在您的系统中乱跑。使用这些工具(和immutable objects)不顾一切地放弃。
从示例中学习
对于使用observable构建的简单JavaFX应用程序,请参阅tic-tac-toe。
有关使用基于FXML的组件构建大型复杂JavaFX应用程序的好方法,请参阅SceneBuilder and SceneBuilderKit的源代码。源代码位于JavaFX mercurial source tree,只需查看并start learning。
阅读JavaFX UI controls architecture。检查JavaFX控件源代码(例如Button和ButtonSkin或ListView和ListViewSkin),以了解如何使用JavaFX结构应用MVC等概念。基于该学习,尝试使用JavaFX控件框架提供的体系结构创建一些自己的自定义控件。通常,当您构建自己的应用程序时,您不需要创建自己的控件(至少从JavaFX Control派生的控件)。 JavaFX Controls体系结构专门用于支持构建可重用控件的库,因此它通常不一定适用于所有目的;相反,它提供了一种经过验证的方法的具体演示,以完成某些事情。采用和改进经过验证的解决方案可以确保您不必要地重新发明内容,并使您能够建立坚实的基础并从其他人的试验中学习。
关于您的具体示例
我建议你一起去:
链接&#34;模型&#34;的最简单方法和&#34;查看&#34;我的计划只是改变&#34;模型&#34; class有一个ObservableList而不是一个ArrayList
也许使用ReadOnlyListWrapper将ObservableList从MachineMonitor公开到外部世界,这样任何东西都不能过度修改它。
设置一些封装视图的其他结构(例如ControlPanel和ControlPanelSkin),并为其提供对只读可观察的MachineMonitor列表的引用。 ControlPanelSkin可以封装TableView,图形或任何您想要用来监视机器的可视旋钮和小部件。
使用这样的结构可以有效地将视图与模型隔离开来。该模型根本不了解UI,ControlPanelSkin实现可以更改为完全不同的可视化表示或技术,而无需更改核心MachineMonitor系统。
以上只是概述了一般方法,您需要根据具体示例进行调整。
答案 1 :(得分:10)
我不同意在你的&#34;模型中使用ObservableList
&#34; class违反了MVC分离。 ObservableList
纯粹是数据表示;它是模型的一部分,而不是视图的一部分。我(and others)use JavaFX properties and collections in model representations in all tiers of my applications。除此之外,我还指出了如何使用(或者至少)绑定到JSF的JavaFX属性。 (我应该提到的是,并非所有人都同意在服务器端使用FX属性的方法;但是我并没有真正看到任何方式来证明它们在某种程度上是视图的一部分。)
由于JavaFX现在是Java标准版的完全成熟部分,因此您也不会添加其他依赖项。 (ObservableList不仅是Java SE的一部分而是ArrayList。)
另外,如果你这样做
List<MachineMonitor> myNonObservableList = ... ;
ObservableList<MachineMonitor> myObservableList = FXCollections.observableList(myNonObservableList);
myObservableList.add(new MachineMonitor());
可观察列表由不可观察列表支持,因此更改也发生在myNonObservableList
中。因此,如果您愿意,可以使用此方法。