2

诚然,我对使用设计模式很陌生,我似乎不确定如何在这里进行。我正在 JavaFX 中构建自定义图形符号。我只是扩展 Parent 并将矩形和圆形添加到我的符号类中,然后在场景中显示该符号对象。

此符号类还注册事件处理程序,如 setOnMouseEntered 和许多其他事件处理程序,以更改符号以响应鼠标事件。我想问的是在哪里存储所有这些事件处理程序最有意义?我不确定他们是否应该改为进入 Controller 类,或者是否因为它们只影响该符号的视图,也许我应该将它们保留在符号的类中,并将 Controller 保留用于必须从 View 进行通信的事物模型,反之亦然。感谢任何可以对此有所了解的人(或者可以为我指出好的资源)!

4

3 回答 3

1

由于您的意图是更改对象..

我会这样理解:

模型:代表您显示的数据的所有内容。在您的情况下,包含所有圆圈的符号类

控制器:如果你以任何方式修改你的模型(你的符号对象),那么只有在你的控制器类中使用方法才允许这样做。Controller是你的层,只有通过这个层你才能访问Model进行修改

视图:显示模型所需的任何东西都可以/应该放置在此部分中。

所以这取决于你,你的程序是否会“记住”当前的选择,或者你的模型是否也有一个变量。我认为这两种方法都应该有效。

1.(在模型中):如果模型中有变量,那么选择一个符号将是一个通过控制器类调用的动作(因为它改变了模型),并且由于模型会改变,它会触发用于更新模型视图的视图类。(视图使用观察者模式来获取新的模型数据并在模型更改时重绘)

2.(在您使用视图和控制器的显示程序中):如果此处“记住”选择,我认为可能会产生一些混乱,因为视图不同(取决于选择)。因此,我建议走 1 路。

请阅读有关 OSR(单一职责)的信息,我不确定如何将 OSR 与 MVC 结合使用,以及扩展您的“真实模型”以添加选择是否会更好,因为这使您的模型不受编辑对象的影响在可能使用相同模型的其他类中可能不需要。如果您始终打算允许编辑符号类,则不必担心将选择变量添加到模型中。

所以关于你的鼠标输入和点击事件,尽量严格:你总是由你的程序本身处理用户输入,但如果它是一个可以理解为对模型的操作的动作,那么你将调用控制器中的一个方法. 您不必遵循这些 MVC 规则,但它应该可以帮助您更好地阅读项目,您可以添加多个自动更新的视图,并且扩展应该更容易。

如果您不确定结构,典型的方法是尝试定义所有可能的解决方案,然后进行比较。尝试找到一种简单的方法(易于理解和易于扩展)。松耦合,OSR 和 DRY 是很好的提示。一般足以尝试尽可能多地应用它们。但也要记住,如果一个解决方案只是遵循设计模式,但它“感觉”太复杂,那么还要考虑构建一个简单的类或其他方法。有时我们构建的复杂性超出了需要。例如,工厂模式和建造者模式是很好的设计模式,但是如果一个类需要非常复杂的配置,但不是多个不同的结构并且与其他对象不相关,那么......在构造函数中包含代码的类可能会采用更好的方法。

作为一个很好的资源,我推荐 OReally 的书籍“Head First Design Patterns”和“Head First Object-Oriented Analysis and Design”。出版商韦斯利的书也很好。通常你可以在你的大学图书馆找到它们免费借阅。尝试找到设计模式的真正用途,这有助于理解它们(为什么有用),并且你会获得一些关于它们使用的经验。

于 2013-04-08T13:12:34.807 回答
1

一般建议

我建议不要尝试直接从抽象概念开始工作,而是在现有代码中查看在 JavaFX 中实现的这些模式的示例,并了解它们是如何在那里编码的。当你找到一些你喜欢的模式时,你可以在你的代码中模拟它们。

在大型编程中,您在整个应用程序或场景中应用 MVC 模式,而在小型编程中,您在特定控件类型中应用模式是不同的。您的问题似乎与后一种情况更相关,因此我将在此答案中主要考虑这一点。


JavaFX 控件 - 皮肤、行为和公共 API

查看 JavaFX 的现有控件代码。对于 a Button,您将拥有:

  1. javafx.scene.control.Button - 用于操作控件的公共 API。
  2. javafx.scene.control.skin.ButtonSkin - 控件的可视化视图。
  3. javafx.scene.control.behavior.ButtonBehavior - 事件绑定(键/鼠标事件等)。

提供ButtonBehavior了一个抽象 api,以便一个按钮可以绑定到不同的平台和用户特定的事件映射,用于键、鼠标和触摸组合。

ButtonSkin允许在不修改公共 API 或行为的情况下完全换入和换出控件的可视化实现。

Button公共 API 提供了一个稳定的 API,按钮的用户可以对其进行编程,以独立于控件实现的任何视觉或行为变化。


删除抽象

虽然皮肤和行为 API 非常适合抽象出行为和外观的实现细节,但它们确实增加了控件实现者的复杂性和开销。您应该考虑您正在创建的控件是否真的需要这种复杂性并评估替代的、更简单的方法。

最简单的方法是扩展现有的窗格并将所有逻辑放在单个扩展类中(或者甚至只是提供构造控制节点的工厂方法)。您失去了抽象以及简单实现可互换性和关注点分离的好处,但是您有一个非常简单的实现。Oracle Mastering FXML 教程中的自定义控件示例就是这种直接扩展机制的一个示例。

我使用的一种稍微复杂的方法是使用一个封装公共 API 和控制状态信息的类以及一个单独的皮肤类来处理事件或 UI 呈现。我喜欢这种方法,因为它清楚地将 JavaFX 特定逻辑和代码与底层控件状态和公共 API 分开,而不会像标准 JavaFX 控件的行为/皮肤/公共 API 方法那样增加太多的概念开销。使用这种方法的一些示例代码在这个井字游戏中


皮肤/行为和公共 API 之间的通信

利用包含控件公共 API 的类中的JavaFX 属性机制。这些属性可以定义控件的公共 API,也可以通过ReadOnlyWrappers等类型封装内部控件状态。

皮肤可以将绑定和侦听器应用于属性,以便在触发侦听器时,皮肤可以触发自身的自动更新以反映新的控件状态。控件的用户可以侦听或绑定到控件的内部状态,以便在该状态更改时采取行动。这种方法的一个示例是ToggleButton 的 selected 属性,其中皮肤会根据按钮是否被选中来改变切换按钮的外观。

当您创建皮肤时,使用对包含控件的公共 api 的反向引用来初始化皮肤和行为(例如SymbolSkin,并SymbolBehaviour具有对 的引用Symbol)。SymbolSkin 或 SymbolBehavior 中的 mouseclickhandler 可以拦截鼠标单击,并将公共 api 上的选定属性切换到 Symbol,然后侦听符​​号上选定属性的更改的用户代码可以在该用户代码不紧密的情况下生效耦合到符号的皮肤或行为。

公共 APISymbol只需要公开一个方法,该方法getSkin()将皮肤作为一个简单的节点返回,可以在场景图中使用。Symbol通过这样做,皮肤和行为的实现对使用公共 API的调用类隐藏。


扩展 Region 并使用 CSS

通过让控件皮肤 extend Region,控件变得可以通过 css 设置样式。我强烈推荐这种方法,因为这意味着控件的许多视觉方面(例如颜色填充、背景、边框、形状等)都可以在JavaFX 丰富的 css 样式语言中进行操作。

执行此操作时,请尝试使用单独的 css 样式类来检测控件外观中的所有节点。这为控件的可视组件提供了挂钩,您可以使用这些挂钩来设置这些组件的样式。使用 CSS 设置图表样式的 Oracle 教程是这种对复杂组件进行样式设置的示例。

要在您的问题中定义不同的符号,您可以创建一个Symbol控件。定义一个SymbolBehaviour用于处理它的用户事件和一个SymbolSkin扩展Region。每个符号实例都可以分配有自己的样式类,公共符号 API 可以提供构造函数或工厂方法,在符号皮肤的区域上设置此样式类。使用-fx-shapecss 说明符根据 svg 路径字符串设置符号形状的样式。

css 样式类名称本身可以硬编码到您的SymbolSkin实现中,并作为公共 API 的一部分进行记录(如标准控件的 CSS 参考指南中所做的那样)。

使用定义控件默认样式的默认 css 模板运送您的控件。


FXML 注意事项

当您有一个由许多需要协调的子控件组成的大型应用程序或场景时,您可以使用FXML之类的东西以声明性方式定义场景。这允许您将 UI 设计与您的命令式编程代码库分开,并确保您不会开始在视图中编写命令式代码。

对于具有 FXML 的真正 MVC 架构,您可能需要的不仅仅是 FXML 文件和用于场景实现的支持控制器,您还需要更高级别的控制机制来换入和换出场景,可能还需要更复杂的事件处理方法,例如作为事件总线,但这超出了这个问题的范围。


有关的

有一个略有不同但相关的问题,应该可以帮助您更好地理解问题域(JavaFX 2.0 - 样式/模板现有控件)。

于 2013-04-08T20:21:23.820 回答
0

看法 :

  • 如果可能,我尝试在 FXML 中应用绑定(双向绑定还不能完成)
  • 如果可以,我会尝试省略控制器(只读阶段是很好的候选者)

控制器 :

  • 我将模型作为构造函数依赖项传递
  • 我在 FXMLLoader 上使用控制器工厂创建控制器
  • 我在初始化方法中设置了绑定

模型 :

  • 如果需要,我会为每个属性定义属性和 getter/setter
  • 我在这部分代码中尽可能多地定义了应用程序的行为

我还在学习 JavaFX,整个技术似乎还不成熟。

随意浏览我用 JavaFX 2.2(IDE:IntelliJ IDEA)编写的一个小型 PoC,网址为http://twittersearch.codeplex.com

于 2013-11-21T15:53:25.247 回答