Подтвердить что ты не робот

Абстрактный класс vs Интерфейс в Java

Мне задали вопрос, я хотел, чтобы мой ответ рассматривался здесь.

Q: В каком сценарии более целесообразно расширять абстрактный класс, а не реализовывать интерфейс (ы)?

A: Если мы используем шаблон шаблона шаблона.

Правильно ли я?

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

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

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

3) мы можем расширить max одного абстрактного класса, но можем реализовать более одного интерфейса

Повторяя вопрос: Есть ли какие-либо другие сценарии, помимо упомянутых выше, где конкретно нам требуется использовать абстрактный класс (один из них - шаблон шаблона для шаблонов, концептуально основанный только на этом)?

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

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

Как всегда есть компромисс, интерфейс дает вам свободу относительно базового класса, абстрактный класс дает вам свободу добавлять новые методы позже. - Эрих Гамма

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

Abstract classes следует в первую очередь использовать для объектов, которые тесно связаны. Interfaces лучше обеспечивают общую функциональность для несвязанных классов.

4b9b3361

Ответ 1

Когда использовать интерфейсы

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

Когда использовать абстрактные классы

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

Когда использовать оба

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

Ответ 2

повторяет вопрос: есть и другой сценарий, помимо этих упомянутых выше, где специально требуется использование абстрактного класса (один - шаблон шаблона шаблона, концептуально основанный на это только)

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

Из личного блога post:

Интерфейс:

  • Класс может реализовывать несколько интерфейсов
  • Интерфейс не может обеспечить какой-либо код вообще
  • Интерфейс может определять только общие статические конечные константы
  • Интерфейс не может определять переменные экземпляра
  • Добавление нового метода оказывает влияние на реализацию классов (техническое обслуживание)
  • JAXB не может работать с интерфейсами
  • Интерфейс не может расширять или реализовывать абстрактный класс
  • Все методы интерфейса общедоступны.

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

Абстрактный класс:

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

Абстрактные классы должны использоваться для (частичной) реализации. Они могут быть средним для ограничения того, как должны выполняться контракты API.

Ответ 3

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

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

Посмотрите статью: http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

Ответ 4

Вы не правы. Существует много сценариев. Это просто невозможно свести к одному правилу с 8 словами.

Ответ 5

По моему мнению, основное отличие состоит в том, что an interface can't contain non abstract methods while an abstract class can. Поэтому, если подклассы имеют общее поведение, это поведение может быть реализовано в суперклассе и, таким образом, унаследовано в подклассах

Также я процитировал следующее из книги

Ответ 6

Что вы должны использовать, абстрактные классы или интерфейсы?

Рассмотрим использование абстрактных классов, если какое-либо из этих утверждений применимо к вашему сценарию:

Вы хотите поделиться кодом между несколькими близкими классами.

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

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

Рассмотрим использование интерфейсов, если какое-либо из этих утверждений относится к вашей ситуации:

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

Вы хотите указать поведение конкретного типа данных, но не обеспокоены тем, кто реализует его поведение.

Вы хотите использовать множественное наследование типа.

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

Ответ 7

Самый короткий ответ - абстрактный класс expand, когда в нем уже реализованы некоторые из функций, которые вы искали.

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

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

Ответ 8

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

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

Ответ 9

Здесь есть много отличных ответов, но я часто нахожу, что использование BOTH-интерфейсов и абстрактных классов - лучший маршрут. Рассмотрим этот надуманный пример:

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

1) Trading system places orders
2) Trading system receives acknowledgements

и может быть захвачен в интерфейсе, ITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

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

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

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

В конкретных реализациях будет много таких грязных методов, как connectToMarket(), но findGoodDeals() - все трейдеры действительно заботятся.

Теперь здесь появляются абстрактные классы. Ваш босс сообщает вам, что валютные трейдеры также хотят использовать вашу систему. И, глядя на валютные рынки, вы видите, что сантехника почти идентична фондовым рынкам. Фактически, connectToMarket() можно повторно использовать дословно для подключения к валютным рынкам. Однако findGoodDeals() - это совершенно другое понятие на валютной арене. Поэтому, прежде чем вы передадите кодовую базу иностранному игроку через океан, вы сначала реорганизуете класс abstract, оставляя findGoodDeals() unimplmented

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Ваша система торговли акциями реализует findGoodDeals(), как вы уже определили,

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

но теперь малыш FX whiz может построить свою систему, просто предоставив реализацию findGoodDeals() для валют; ей не нужно повторно использовать соединения сокетов или даже методы интерфейса!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

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

Примечание. можно задаться вопросом, почему findGreatDeals() не является частью интерфейса. Помните, что интерфейс определяет наиболее общие компоненты торговой системы. Другой инженер может разработать ПОЛНОСТЬЮ РАЗЛИЧНАЯ торговая система, где они не заботятся о поиске хороших сделок. Интерфейс гарантирует, что торговый центр может также взаимодействовать с их системой, поэтому предпочтительнее не перепутывать интерфейс с такими концепциями приложений, как "отличные сделки".

Ответ 10

За последние три года многое изменилось с добавлением новых возможностей для взаимодействия с выпуском Java 8.

Из документации oracle страница на интерфейсе:

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

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

Еще одно соображение, чтобы предпочесть абстрактный класс по интерфейсу:

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

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


Что касается второй части вашего вопроса, которая действительна для большинства языков программирования, включая java, до java-8 release

Как всегда есть компромисс, интерфейс дает вам свободу относительно базового класса, абстрактный класс дает вам свободу добавлять новые методы позже. - Эрих Гамма

Вы не можете пойти и изменить интерфейс, не изменяя в коде много чего другого.

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

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

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

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

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

Подробнее см. эти связанные вопросы:

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

Как я должен объяснить разницу между интерфейсом и абстрактным классом?

Вкратце: Баланс теперь больше наклоняется к интерфейсам.

Существуют ли какие-либо другие сценарии, помимо упомянутых выше, где конкретно нам требуется использовать абстрактный класс (один из них - шаблон шаблона для шаблонов, концептуально основанный только на этом)?

В некоторых шаблонах проектирования используются абстрактные классы (поверх интерфейсов), кроме шаблона метода шаблонов.

Шаблоны создания:

Abstract_factory_pattern

Структурные шаблоны:

Decorator_pattern

Поведенческие модели:

Mediator_pattern

Ответ 11

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

Ответ 12

Abstract classes should be extended when you want to some common behavior to get extended. Абстрактный суперкласс будет иметь общее поведение и будет определять абстрактный метод/конкретное поведение, которое должны реализовывать подкласс.

Interfaces allows you to change the implementation anytime allowing the interface to be intact.

Ответ 13

Это мое понимание, надеюсь, что это поможет

Абстрактные классы:

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

Интерфейсы:

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

Ответ 14

Использование абстрактного и интерфейса:

У одного есть "Is-A-Relationship", а у другого есть "Has-A-Relationship"

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

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