如何使用对象的原始 class 转换引用?

How to cast a reference with an object's original class?

我正在开发用于处理的 GUI 库,我有一个 class Component。我有一堆扩展 Component 的其他 classes:LabelButton(扩展 Label)、PanelIcon.这些 classes 仅包含 "logic" 部分(位置、文本、函数检查是否被单击等...)。

class Panel 内部有 ArrayListComponent,您可以向其中添加按钮、标签等...

为了显示组件,我决定使用 class Theme,其中包含函数 display(Component component) 的一些重载(一个用于 Label,一个用于 Button,一个用于 Panel 等...)。

display(Panel panel) 内部,在某些时候,我显示面板的所有子项,但是,没有将它们(子项)视为 ButtonLabel,而是全部为 Component。我该如何解决这个问题?

1) 我已经尝试在 classes ComponentButton 等中使用方法 display()...它部分起作用,但它给出一些 "coding problems":要覆盖函数显示,您必须创建一个新的 class(示例:GreenBackgroundButton extends Button{})。此外,通过将所有功能放在外部 class 中,您可以使用单个 class 控制您程序的所有 rapihcs,因此您可以使用单个功能对所有组件具有相同的背景 displayBackground()等...

2) instanceof 无法使用,因为,如果我必须使用它来转换面板的子项,用户将无法创建自定义组件,因为它们将显示为 Component 不像 TextField(示例)。

3) 我试过直接转换 display((Button)panel.getChildren.get(0)),但是,正如它所显示的那样,当我使用标签时,它给出了一个错误(如预期的那样)。

4) 我也试过这样转换:panel.getChildren().get(0).getClass().cast(panel.getChildren().get(0)),但它不起作用,我不知道为什么。 (我尝试了它的所有变体,比如创建外部对象等...)

5) 如果需要更多代码,可以询问...

public void display(Panel panel) {
    println("panel");
    if (panel.isVisible()) {
      pushMatrix();
      translate(panel.getX(), panel.getY());
      displayBackground(panel, #AAAAAA);

      for (int i = 0; i < panel.getChildren().size(); i++) {
        this.display(panel.getChildren().get(i).getClass().cast(panel.getChildren().get(i))); //THIS IS THE LINE WITH THE ISSUE
        //println(panel.getChildren().get(i).getClass().cast(panel.getChildren().get(i)));
      }
      popMatrix();
    }
  }


Theme basicTheme;
Button close;
Panel panel;

void settings() {
  size(400, 600, P2D);
}

void setup() {
  basicTheme = new Theme();

  close = new Button();
  close.setBounds(10, 10, 100, 25);
  close.setText("close");

  panel = new Panel();
  panel.setBounds(50, 200, 200, 200);
  panel.add(close);
}

void draw() {
  background(255);

  basicTheme.display(panel);
}

我希望在 canvas 面板内看到一个可用的按钮,而不是看到一个组件。我现在没有想到任何特别的错误。

使用 instanceof 几乎总是一种 hack,并且可能是糟糕设计的征兆。

您所描述的内容听起来与名为 Abstract Window Toolkit (AWT) 的现有 Java 库完全一样,因此您可以考虑 "borrowing" 他们的一些设计模式。

  • Component是一个抽象class,它定义了一个抽象paint()函数。 paint() 函数接受一个 Graphics 参数。稍后会详细介绍。
  • ButtonLabel 扩展 Component 并覆盖 paint() 函数。
  • Graphics 是一个包含 drawRect()setBackground() 等函数的 class。它封装了共享绘图代码,类似于我认为您的 Theme class 会做的。

如果我是你,我会考虑对你的图书馆采取类似的方法。

我会尝试解决您的一些其他评论:

Example: GreenBackgroundButton extends Button{}

喜欢composition over inheritance这种情况。您不需要扩展 Button 来设置背景。相反,在 Button() class(或 Component class)中有一个 setBackground() 函数。

Also, by putting all the function in an external class, you can control all the rapihcs of you Program with a single class, so you can have the same background for all the components with a single function displayBackground() etc.

听起来这属于你的 Component class。

此外,退一步说,我鼓励您避免 over-engineer 解决方案的诱惑。您可能认为您需要一个具有多个继承级别和许多不同 class 的复杂设计,但很可能一个更简单的设计可能会为您提供几乎所有您需要的东西。具体来说,我没有看到将任何代码提取到 Theme class 中有什么巨大好处。我可能会将所有内容直接放在我的组件子 class 中,例如 ButtonLabel.