Зачем создавать абстрактные классы и интерфейсы? - PullRequest
8 голосов
/ 03 марта 2010

Ну, я собирался спросить, в чем разница, но на это уже отвечали. Но теперь я спрашиваю, почему они сделали эти различия? (Я говорю о Java здесь, я не знаю, относится ли это к другим языкам)

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

Есть ли какое-то преимущество в том, что я не могу писать тело метода или расширяться несколько раз, чего я не вижу?

Ответы [ 7 ]

10 голосов
/ 03 марта 2010

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

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

5 голосов
/ 03 марта 2010

Множественное наследование в C ++ приводит к семантическим неопределенностям, таким как проблема наследования алмазов . МИ довольно мощный, но имеет сложные последствия.

Создание интерфейсов в особом случае также повышает наглядность концепции как средства сокрытия информации и уменьшения сложности программы. В C ++ определение чистых абстрактных основ является признаком зрелого программиста. В Java вы сталкиваетесь с ними на более ранней стадии развития программиста.

3 голосов
/ 03 марта 2010

Многократное наследование труднее реализовать на языке (на самом деле компилятор), так как это может привести к определенным проблемам. Эти вопросы обсуждались здесь ранее: Какая именно проблема с множественным наследованием .

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

2 голосов
/ 03 марта 2010

Рассмотрим этот пример:

public abstract class Engine
{
  public abstract void switchPowerOn();
  public abstract void sprinkleSomeFuel();
  public abstract void ignite();

  public final void start()
  {
    switchPowerOn();
    sprinkleSomeFuel();
    ignite();
  }
}

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

Этот шаблон называется «Метод шаблона формы» и, откровенно говоря, является для меня единственным разумным использованием абстрактных классов в Java.

1 голос
/ 03 марта 2010

Создание их одной вещи - это путь, по которому ребята из Scala выбрали Traits, интерфейс, который может иметь методы и поддерживать множественное наследование.

Я думаю, что интерфейсы, для меня, чисты в том смысле, что они определяют только требования (проектирование по контракту), тогда как абстрактные классы определяют общее поведение (реализацию), поэтому другой инструмент для другой работы? Интерфейсы, вероятно, позволяют более эффективно генерировать код во время компиляции?

0 голосов
/ 03 марта 2010

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

Абстрактный класс позволяет вам определять природу, которую вы хотите, чтобы она была универсальной, а не напрямую инстанцируемой, потому что она должна быть специализированной. Вы знаете, как выполнять некоторые задачи высокого уровня (например, принимать решение в соответствии с некоторыми параметрами), но вы не знаете деталей для некоторых действий более низкого уровня (например, вычислять некоторые промежуточные параметры), потому что это зависит от выбора реализации. Альтернативой для решения этой проблемы является шаблон проектирования стратегии . Он более гибкий, допускает переключение стратегий во время выполнения и поведение Null, но при этом он более сложный (и переключение во время выполнения не всегда необходимо). Более того, вы можете потерять некоторые , что означает и средства ввода (полиморфизм и проверка типов становятся немного сложнее, потому что Стратегия - это компонент, а не сам объект).

Абстрактный класс = is-a, Стратегия = has-a

Редактировать: что касается множественного наследования, см. Ответ Pontus Gagge.

0 голосов
/ 03 марта 2010

Другой подход, который вы описываете, - это подход, используемый C ++ (например, mixins). Проблемы, связанные с таким «множественным наследованием», довольно сложны и имеют несколько критических замечаний в C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...