Разрешать методу Java вызывать методы подкласса объекта-параметра?

#java

#java

Вопрос:

Я работаю над небольшим университетским заданием. Устав от написания трех строк кода для добавления кнопок, я написал небольшую служебную функцию:

 private JButton addButton(Container container, String text) {

    JButton button = new JButton(text);
    button.addActionListener(this);
    container.add(button);

    return button;
}
  

Затем, конечно, появился служебный метод для добавления текстовых полей:

 private JTextField addInput(Container container, int width) {

    JTextField input = new JTextField(width);
    input.addActionListener(this);
    container.add(input);

    return input;
}
  

Как вы можете видеть, они почти идентичны. Итак, я попытался уменьшить количество строк, используя всемогущий метод, который добавлял бы что угодно к любой другой вещи.

 private Component addComponent(Container container, Component component) {

    component.addActionListener(this);
    container.add(component);

    return component;
}
  

Теперь я должен признать, что начинаю думать, что, возможно, эти сверхмалые служебные функции немного абсурдны.

Однако, несмотря на это, мой всемогущий addComponent метод не сработал. Вместо этого жаловаться, что у Component них нет ActionListeners .

Единственный способ, которым я могу обойти это, — это иметь MyJButton и MyJTextField оба из которых наследуются от MyComponent того addActionListener , у которого есть метод. Первоначальная цель упрощения и устранения повторений была выброшена из окна?

Как это можно / должно быть сделано? Я новичок в Java и строго типизированных материалах!

Ответ №1:

Я бы сказал, что ваш текущий подход (куча похожих вспомогательных методов) настолько хорош, насколько вы сможете.

Некоторые вещи неэлегантны, и вы мало что можете с этим поделать.

Риск попытки объединить методы (в соответствии с ответом @leonbloy) заключается в том, что вы заменяете безопасность статического типа безопасностью типа во время выполнения; т. е. ClassCastExceptions при сбое приведения типов … или хуже.


С лингвистической точки зрения, что необходимо, так это способ для приложения «украсить» существующую иерархию классов дополнительным методом (или методами) и иметь методы, вызываемые полиморфной диспетчеризацией, так же, как вы делаете с обычными методами экземпляра.

Это можно смоделировать с использованием шаблона декоратора, но для этого требуется некоторая довольно тяжеловесная инфраструктура … если в иерархии классов нет перехватов для поддержки встроенного шаблона.

Ответ №2:

Проблема в том, что нет интерфейса, который предоставляет

 addActionListener(ActionListener l)
  

если бы это было так, вы могли бы сделать

 public <T extends Component amp; ActionListenable> Component addComponent(Container container, T component) {

    component.addActionListener(this);
    container.add(component);

    return component;
}
  

Предполагая, что поддельный ActionListenable является вышеупомянутым интерфейсом.

Ответ №3:

Существует несколько подходов. Если вы точно знаете, что ваш метод addComponent будет действовать только с параметрами JTextField и JButton , вы можете выполнять явные приведения

  if (component instanceof JButton){
  ((JButton)component).addActionListener(this); 
 }
 else if (component instanceof JTextField){
  ((JTextField)component).addActionListener(this);
 }
  

Не очень элегантно, не очень хорошая практика, но этого может быть достаточно в вашем сценарии.

Если вы хотите вызвать, addActionListener если у Component есть этот метод, вы можете использовать отражение — но я подозреваю, что это было бы излишним для вашей цели.

PS: В случае, если вам это более понятно, это было бы эквивалентно второй строке:

   JButton button = (JButton)component; // explicit cast -we know for sure that this is a JButton 
  button.addActionListener(this); 
  

Комментарии:

1. Это было бы неподходящим местом для использования отражения. Вы бы просто делали то же самое (вероятно) менее эффективным и (определенно) более хрупким способом.