Как я могу гарантировать, что реализация интерфейса расширяет определенный класс?

У меня есть два типа редакторов. Одним из них является подкласс JTextArea и один является подклассом JTable (JTextArea а также JTable оба подклассы JComponent). Я хочу, чтобы мои два класса, TextAreaEditor а также TableEditor реализовать интерфейс Editorкоторый просто имеет метод public String getText(),

Я хочу, чтобы код клиента просто использовал Editor интерфейс. Проблема в том, что все мои Editorс использованием методов JComponent, лайк setEnabled(bool), Так как мой редактор - это интерфейс, и я не могу заставить его расширять JComponent, я должен использовать реализации вместо интерфейса при вызове этих методов. Поэтому я подумал, что вместо использования интерфейса я могу просто сделать Editor подкласс JComponent и заставить мои занятия расширять это. Вопрос в таких классах, как TextAreaEditor уже расширить какой-то класс, как JTextAreaпоэтому я не могу заставить их продлить другой класс.

Есть ли способ убедиться, что мой Editor класс является JComponent, и что мои конкретные классы редактора Editorс и подклассы JComponent?

6 ответов

Если вы предоставите интересующие вас методы JComponent в подклассе вашего интерфейса редактора, они будут "задним числом" реализованы вашим классом.

Вот некоторый код, чтобы продемонстрировать идею:

interface Editor { 
  String getText(); 
}

interface SwingEditor extends Editor { 
  void setEnabled(bool); // has to match *exactly* the signature from JComponent
}

class TableEditor extends JTable implements SwingEditor {
   // implement your getText(), and anything else you need 
   // no need to implement setEnabled, as it is provided by JTable
}

SwingEditor te = new TableEditor();
te.setEnabled(true); // will call JComponent's method

Я предполагаю, что вам действительно нужно наследование, в общем, часто составление является лучшим вариантом для кода Swing UI.

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

Иметь свой TextAreaEditor а также TableEditor оба имеют экземпляр JComponent им нужно. Добавьте все необходимые методы в свой интерфейс, а затем делегируйте эти вызовы JComponet,

Например:

public class TextAreaEditor implements Editor {
     private final JTextArea textArea = new JTextArea();

     public void setEnabled(bool isEnabled) {
          return textArea.setEnabled(isEnabled);
     }

     //... your own methods plus other methods from JComponent
}

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

Дайте мне знать, если вам нужно больше разъяснений.

Если вам действительно нужно Editor класс, чтобы быть JComponent также вы можете просто задокументировать это и выполнить приведение в своем коде. Не самое аккуратное решение, но, безусловно, самое простое.

Другой подход заключается в добавлении дополнительного метода к Editor интерфейс:

public JComponent getComponent();

где твой Editor экземпляры могут реализовать этот метод, просто возвращая this,

Преимущество последнего подхода заключается в том, что вы можете использовать все JComponent методы, и не нужно дублировать их в вашем интерфейсе, и прийти к выводу, что через 2 месяца вы забыли добавить один из JComponent методы к вашему интерфейсу

Следующий дизайн заботится об этом:

public class TextAreaEditor extends JTextArea implements Editor {
//provide your implementation of getText()
//setEnabled(bool) doesn't have be implemented as JComponent will provide
}

TextAreaEditor te = new TextAreaEditor();
te.setEnabled(true); // will call JComponent's impl

Согласно приведенному выше коду, ваши собственные конкретные реализации редактора (TextAreaEditor) являются редактором и подклассом JComponent.

Я бы, вероятно, создал бы новую таблицу и класс textarea, расширяя их соответствующий суперкласс, и реализуя интерфейс редактора, подобный так

public class JTextAreaEditor extends JTextArea implements Editor {
...
}

Затем используйте композицию, чтобы раскрыть методы интерфейса редактора.

    public class JTextAreaEditor extends JTextArea implements Editor {
       private Editor editor;

       public String getValue() {
          return editor.getValue();
       }
       ...
    }

Я думаю, что ваш аргумент просто неверен: для интерфейса (редактора) вам не нужно беспокоиться о том, как реализованы реализации. Вы сказали, что вся ваша реализация редактора должна быть JComponent. Это именно то, что происходит сейчас, но никогда не нужно быть "требованием" для того, чтобы быть "редактором". У конструкции Editor нет причин навязывать это, если реализация соответствует тому, что запрашивает Editor (getText()).

То, о чем вы говорите, в основном является базовым классом по умолчанию для "обычных" реализаций редактора. Еще раз отметим, что выбор реализации этого базового класса - это их выбор, если они соответствуют интерфейсу вашего редактора.

public interface Editor {
    String getText();
}

public abstract class JComponentEditor extends JComponent 
        implements Editor {
    //.....
}

public TextAreaEditor extends JComponentEditor {
    public String getText() {
        // implements TextAreaEditor's version of getText
    }
}

РЕДАКТИРОВАТЬ: Я думаю, что я немного неправильно понял вопрос OP. Как бы то ни было, главный аргумент в моем ответе по-прежнему остается верным: не имеет смысла принудительно применять "... что мой класс Editor является JComponent, а мои конкретные классы редактора являются Editors и подклассами JComponent" ". Это просто деталь реализации редактора

Другие вопросы по тегам