简短的答案就是“您必须那样做,因为这就是API的编写方式”。当然,您可能真正要问的是为什么要这样编写API。我认为这实际上是两个(相关的)问题。一种与方法名称有关,以及该方法的作用,另一种与实际的API设计有关。
通常,在计算中,重用现有的问题解决方案通常是有益的。(知道何时进行此 *** 作是一门艺术,但是在这两种情况下,显然都是有益的。)以两种不同的方式,此API设计重用了现有的解决方案来解决众所周知的问题,因此使之成为现实。对于以前遇到过这些解决方案的程序员来说,更容易理解和使用。
场景图
从总体上看,考虑一下通用用户界面的整体结构。有一个大容器(包含JavaFX场景的根源),其中包含各种UI组件。其中一些可能是简单的控件,例如按钮和标签等,其中一些可能是其他容器,这些容器又包含各种UI组件。当然,其中一些也可能是容器,依此类推。如果不强加某种结构,这可能变得复杂且难以使用。
为了理解结构,我们将其抽象化。有一个根节点,它有零个或多个其他节点的集合。每个节点都有零个或多个其他节点的集合,依此类推。这是计算中非常著名的抽象结构,称为“树”,基本上每个计算机程序员(无论他们使用哪种语言)都熟悉。因此,如果我们将其视为树结构,因为我们已经很熟悉它,那么我们可以使复杂性更易于使用。为了将其视为树结构,我们对树状方面使用标准名称。每个节点(根节点除外)都只有一个“父”(它所属的容器):因此您将在
Node该类中找到一个方法(“节点”是树结构中的另一种术语),称为
getParent(),它可以访问父节点(包含当前节点的容器)。同样,包含其他节点的UI元素(节点)具有一种称为的方法
getChildren(),该方法返回当前节点中包含的所有节点的集合。Oracle
JavaFX教程在“ 场景”图上有一节对此进行了描述,其中包含许多精美的图表和相关代码。
简而言之,之所以有一个方法被称为,
getChildren()是因为我们认为UI中所有事物的集合都是树形结构,并且此方法名称准确地描述了该方法在所有对象集合的上下文中的作用。
UI元素是一棵树。具有一点经验的程序员可以立即识别术语“节点”,“父”和“子”,并帮助他们理解整体结构并与之合作。他们基本上可以立即推断出
getChildren()返回立即包含在该容器中的所有UI元素的列表(该容器是
StackPane您的示例中的)。
的API设计
Pane(例如
StackPane)
要考虑API设计,请考虑 *** 作中可能包含的所有内容
StackPane。如您所见,您可能想向中添加一个新的UI元素(“节点”)
StackPane,因此您可能想要一个名为的方法
add(...),该方法接受一个
Node。但是,您可能还需要或想要做很多其他事情:
- 从节点中删除一个节点
StackPane
- 将整个节点集合添加到
StackPane
- 从中删除整个节点集合
StackPane
- 从(清除)移除所有节点
StackPane
- 由于节点在堆栈窗格中的顺序很重要(它定义了z顺序,即,如果节点重叠,它定义了哪些绘制在前面,哪些绘制在后面),因此您可能想在特定位置(前面)插入一个节点的东西,但后面的东西)
- 删除“后”,前或指定位置的节点
- 还有很多很多
因此,
StackPane该类的设计师可以编写所有这些方法,但是有更好的方法。
如果考虑实现
StackPane,则需要某种方式来跟踪其中包含的节点(UI元素)。这些节点的顺序很重要,因此我们必须对其进行跟踪,并且需要有一种很好的方法来定义上面列出的所有功能。
StackPane该类(或其父类
Pane)的作者本可以构建一个数据结构来从头开始执行此 *** 作,但是标准库中已经存在一个。包含某种特定类型的对象的集合并跟踪其顺序的数据结构称为1,并且该接口是
每个Java程序员都熟悉
的接口。
List
List
__
因此,如果考虑到的实际实现,则
StackPane可以在堆栈窗格本身中为上面列出的所有功能定义方法。最终看起来有些东西(真的会比这更复杂,我只想在这里指出这一点)就像
public class StackPane { private final List<Node> children = new ArrayList<>(); // or some other list implementation... public void add(Node node) { children.add(node); } public boolean remove(Node node) { return children.remove(node); } public void add(int index, Node node) { children.add(index, node); } public boolean remove(int index) { return children.remove(index); } public void addAll(Collection<Node> nodes) { children.addAll(nodes); } // lots more methods like this... // lots of layout pre omitted...}
我认为你说对了。所有这些代码实际上并没有做什么。只是调用已定义的行为。因此,可以
StackPane通过仅提供对列表本身的访问权限2来向用户提供完全相同的功能,而不用使用这种API肿的API
:
public class StackPane { private final List<Node> children = new ArrayList<>(); public List<Node> getChildren() { return children ; } // layout pre omitted...}
现在,该类不再那么blo肿,API也不再那么blo肿,此外,用户会收到
List,如前所述,这是一种非常众所周知的对象类型。假设他们具有一定的Java经验,那么新的JavaFX程序员将已经熟悉该API,
List并且无需学习太多新知识就可以使用它。因此,程序员现在可以执行此 *** 作(使用非常规方式放置代码,并插入程序员的思想):
StackPane pane = new StackPane();Button button = new Button("OK");pane.getChildren() // oooh, a List, I know how those work .add(button);List<Label> lotsOfLabels = Arrays.asList(new Label("One"), new Label("Two"), new Label("Three"));pane.getChildren() // still a list, I know more things I can do here: .addAll(lotsOfLabels);pane.getChildren().remove(button);pane.getChildren().clear();
我们有一个高兴的程序员,他立即知道API,并且在第一次接触JavaFX中的场景图时立即产生了成果,因此,一个高兴的老板也看到了编程团队的高生产力。
因此,总而言之,通过简单地公开
List子节点,API即可公开处理的内容所需的所有功能
StackPane,而无需在
StackPane类中添加大量方法
并 以利用现有知识的方式来实现每个Java程序员。
脚注
- 实际上,
Pane
s需要的功能比以下中定义的要多List
:他们需要一种方便的方式来了解列表何时更改(通过添加或删除节点)(因为发生这种情况时窗格需要重新计算其布局)。因此,JavaFX团队定义了一个List
名为的子接口,该子接口ObservableList
具有的所有功能,List
并添加了“观察”列表的功能。 - JavaFX团队在这里必须认真考虑一件事: 所有 定义的功能是否 都
List
适合于子节点的集合?如果该List
接口定义了一些在这里实际上没有用的方法,那么使用此实现可能是一个坏主意,并且在第一个代码块中建议使用的更肿的API实际上可能是一个更好的选择。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)