2009-12-19 3 views
4

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

Итак, что лучше всего здесь? Я говорю о таких проблемах, как:

1) Должен ли абстрактный класс реализовать интерфейс или его дочерние классы? Должны ли каждый класс? Мне кажется, что только абстрактный класс должен. Конечно, все классы могли реализовать интерфейс, но это кажется излишним, потому что дети абстрактного будут «наследовать» интерфейс, потому что они расширяют абстрактный класс.

2) Учитывая, что абстрактный класс реализует части интерфейса, должен ли он также объявлять абстрактные методы для методов, которые он не реализует? Мне кажется, что это правильно, но в некотором роде это кажется излишним, потому что дети абстрактного должны будут реализовать эти методы для компиляции.

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

ответ

2

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

8

Принцип, который должен помочь вам здесь. DRY: Не повторяйте себя (http://en.wikipedia.org/wiki/Don%27t_repeat_yourself).

В этом контексте DRY означает, что вы не должны выполнять ненужную работу.

Итак, для вашего 1-го вопроса абстрактный класс должен реализовать интерфейс, поскольку он избавляет вас от повторения предложения «реализует X» на каждом конкретном классе.

Что касается второго вопроса, нет смысла повторять методы интерфейса в абстрактном классе, который его реализует. Это избыточная работа. Более того, когда интерфейс развивается/изменяется, вам нужно будет изменить методы (абстрактные) в абстрактном классе, который является головной болью. В какой-то момент вы пропустите обновление некоторых методов, и конкретный класс должен будет реализовать их напрасно.

+0

+1, добавлю, что если бы я лично увидел конкретный класс, который реализовал Foo, а также расширенный AbstractFoo, мой первый инстинкт был бы в том, что Foo и AbstractFoo могут даже не быть связанными. Увеличьте путаницу, поскольку имена становятся менее очевидными. – PSpeed

+1

интерфейсы не предназначены для развития и изменения ... – TofuBeer

+0

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

0

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

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

Вы не должны избыточно объявлять абстрактные методы в абстрактном классе, который уже находится в интерфейсе.

2

Наиболее гибкий способ программирования для этого:

  1. Снабдите интерфейс
  2. Обеспечить абстрактный класс, который реализует интерфейс
  3. Обеспечить конкретные классы, либо расширяющие от абстрактного класса или продлить из другого класса и реализовать интерфейс
  4. Alway (если вы не можете) объявить переменные/параметры/константы как интерфейс, а не абстрактный класс или конкретные классы

Нет смысла в том, чтобы конкретные классы реализовали интерфейс (более подробно). Нет смысла в абстрактном классе повторять абстрактные методы из интерфейса.

Выполняя # 4, вы можете использовать все классы, реализующие интерфейс, - если бы вы использовали абстрактный класс, вместо этого классы, реализующие интерфейс, но не расширяющие абстрактный класс, не могут использоваться.

(позже часть)

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

1

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

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

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