Почему интерфейсы предпочтительнее абстрактных классов? - PullRequest
35 голосов
/ 12 марта 2009

Я недавно посетил интервью, и они задали мне вопрос «Почему интерфейсы предпочтительнее абстрактных классов?»

Я попытался дать несколько ответов, таких как:

  • Мы можем получить только одну Расширяемую функциональность
  • они на 100% абстрактные
  • Реализация не жестко закодирована

Они попросили меня взять любой из API JDBC, который вы используете. «Почему они интерфейсы?».

Могу ли я получить лучший ответ на этот вопрос?

Ответы [ 23 ]

3 голосов
/ 15 марта 2009

С уважением не согласен с большинством вышеперечисленных постеров (извините! Мод, если хотите :-))


Во-первых, ответ «только один суперкласс» хромает. Любой, кто дал мне этот ответ в интервью, быстро возразит: «C ++ существовал до того, как в Java и C ++ было несколько суперклассов. Как вы думаете, почему Джеймс Гослинг разрешил только один суперкласс для Java?»

Поймите философию вашего ответа, иначе вы будете тостом (по крайней мере, если я опрошу вас).


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

Пример:

public void foo(Hashtable bar);

против

public void foo(Map bar);

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


В-третьих, интерфейсы позволяют публичным методам в конкретных реализациях классов быть «закрытыми». Если метод не объявлен в интерфейсе, метод не может быть использован (или неправильно использован) классами, которые не используют этот метод. Что подводит меня к пункту 4 ....


В-четвертых, Интерфейсы представляют собой минимальный контракт между реализующим классом и вызывающей стороной. Этот минимальный контракт точно определяет , как конкретный исполнитель ожидает использования и не более. Вызывающему классу не разрешается использовать любой другой метод, не указанный в «контракте» интерфейса. Используемое имя интерфейса также изменяет ожидания разработчика относительно того, как они должны использовать объект. Если разработчик прошел

public interface FragmentVisitor {
    public void visit(Node node);
}

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


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

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

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


Да, я знаю, что, конечно, разработчик может использовать некоторые «специальные» знания, чтобы привести объект к другому более широкому интерфейсу или самому конкретному классу. Но такое приведение в действие нарушает ожидаемый контракт, и разработчик должен ударить лосося.

2 голосов
/ 30 июля 2011

Если они думают, что X лучше, чем Y, я не буду беспокоиться о том, чтобы получить работу, я не хотел бы работать на того, кто заставлял меня переходить от одного дизайна к другому, потому что им говорили, что интерфейсы - лучшие. Оба хороши в зависимости от ситуации, иначе почему язык решил добавить абстрактные классы? Конечно, языковые дизайнеры умнее меня.

2 голосов
/ 03 декабря 2012

Это проблема «множественного наследования». Мы можем «расширять» не более одного класса abstarct одновременно через другой класс, но в интерфейсах мы можем «реализовать» несколько интерфейсов в одном классе. Таким образом, хотя Java в целом не обеспечивает множественное наследование, но с помощью интерфейсов мы можем включить в него свойство множественного наследования.

Надеюсь, это поможет !!!

1 голос
/ 13 марта 2009

Существует одна причина, не упомянутая выше.

Вы можете легко декорировать любой интерфейс с помощью java.lang.reflect.Proxy, позволяющего добавлять пользовательский код во время выполнения к любому методу в данном интерфейсе. Это очень мощный.

См. http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html для учебника.

1 голос
/ 12 марта 2009

interface s - более чистый способ написания чисто абстрактного класса. Вы можете сказать, что реализация не вошла (конечно, вы можете захотеть сделать это на определенных этапах обслуживания, что делает интерфейсы плохими) Вот и все. Для клиентского кода почти нет различий.

JDBC - действительно плохой пример. Спросите любого, кто пытался реализовать интерфейсы и поддерживать код между выпусками JDK. JAX-WS еще хуже, добавляя методы в обновлениях.

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

С другой стороны, для интерфейсов компилятор не может выполнить некоторые невозможные преобразования / instanceof s.

1 голос
/ 07 ноября 2016

интерфейс не заменяет абстрактный класс .

Предпочитают

интерфейс: Для реализации контракта несколькими несвязанными объектами

абстрактный класс: Для реализации одинакового или различного поведения среди нескольких связанных объектов


См. Этот связанный вопрос SE для вариантов использования как интерфейса, так и абстрактного класса

Интерфейс против абстрактного класса (общий OO)

Вариант использования:

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

Если вам нужно реализовать возможность для многих нереализованных объектов, абстрактный класс не служит цели, и вам нужно выбрать interface .

0 голосов
/ 12 марта 2009

Вы можете реализовать несколько интерфейсов, но, в частности, c # вы не можете иметь несколько наследований

0 голосов
/ 12 марта 2009

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

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

0 голосов
/ 12 марта 2009

Потому что интерфейсы не принуждают вас к некоторой иерархии наследования.

0 голосов
/ 25 ноября 2009

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

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