Как привести ссылку на исходный класс объекта? - PullRequest
1 голос
/ 19 мая 2019

Я работаю над библиотекой GUI для обработки, и у меня есть класс Component.У меня есть куча других классов, которые расширяют Component: Label, Button (что расширяет Label), Panel и Icon.Эти классы содержат только «логическую» часть (положение, текст, проверка функций, если они нажаты и т. Д.).

Класс Panel имеет внутри ArrayList из Component,и вы можете добавить к нему кнопки, метки и т. д. *

Для отображения компонентов я решил использовать класс Theme, внутри которого есть несколько перегрузок функции display(Component component) (одна для Labelодин для Button, один для Panel и т. д.).

Внутри display(Panel panel), в какой-то момент, я отображаю все дочерние элементы панели, но настаиваю на том, чтобы их обработать (дети) как Button или Label, все они рассматриваются как Component.Как я могу решить эту проблему?

1) Я уже пытался использовать метод display() внутри классов Component, Button и т. Д. ... он работает частично, но дает некоторые "проблемы кодирования": переопределитьДля отображения функции необходимо создать новый класс (Пример: GreenBackgroundButton extends Button {}).Кроме того, поместив все функции во внешний класс, вы можете контролировать все программы вашей программы с помощью одного класса, так что вы можете иметь одинаковый фон для всех компонентов с помощью одной функции displayBackground() и т.д ...

2) instanceof нельзя использовать, потому что, если мне придется использовать его для приведения дочерних элементов панели, пользователь не сможет создавать пользовательские компоненты, поскольку они будут отображаться как Component notкак 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);
}

Iожидайте увидеть на холсте рабочую кнопку внутри панели вместо того, чтобы видеть компонент.У меня нет какой-то конкретной ошибки, о которой я могу думать прямо сейчас.

1 Ответ

1 голос
/ 19 мая 2019

Использование instanceof почти всегда является хаком и, вероятно, является признаком плохого дизайна.

То, что вы описали, звучит в точности как существующая библиотека Java, называемая Abstract Window Toolkit (AWT), так что вы можете подумать о "заимствовании" некоторых из их шаблонов проектирования.

  • Component - это абстрактный класс, который определяет абстрактную функцию paint().Функция paint() принимает аргумент Graphics.Подробнее об этом за секунду.
  • Button и Label расширяют Component и переопределяют функцию paint().
  • Graphics - это класс, который содержит такие функции, как drawRect() и setBackground().Он инкапсулирует общий код рисования, аналогично тому, что, я думаю, ваш класс Theme сделает.

Если бы я был вами, я бы рассмотрел аналогичный подход для вашей библиотеки.

Я попытаюсь ответить на некоторые другие ваши комментарии:

Пример: GreenBackgroundButton расширяет Button {}

Favor композиция по наследованию для таких случаев, какэтот.Вам не нужно расширять Button, чтобы установить фон.Вместо этого имейте функцию setBackground() в классе Button() (или в классе Component).

Кроме того, поместив все функции во внешний класс, вы можете контролировать всеВаши программы Запрограммируйте с одним классом, так что вы можете иметь один и тот же фон для всех компонентов с одной функцией displayBackground () и т. д.

Похоже, это относится к вашему классу Component.

Также, сделав шаг назад, я бы посоветовал вам избежать соблазна сверхинженерного решения.Вы можете подумать, что вам нужен сложный дизайн с несколькими уровнями наследования и множеством разных классов, но, скорее всего, более простой дизайн, вероятно, даст вам почти все, что вам нужно.В частности, я не вижу огромных преимуществ при извлечении какого-либо кода в класс Theme.Я, вероятно, поместил бы все непосредственно в мои подклассы компонентов, такие как Button и Label.

...