2012-02-29 2 views
25

Я обсуждал с коллегой, который настаивал на том, что в таких языках, как Java и C#, никогда не было причин использовать базовый класс Pure Abstract, поскольку это просто означает, что вы неспособность обойти отсутствие множественного наследования.Разница между чистым абстрактным классом и интерфейсом

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

Например, если бы я хотел определить тип Bird, где я хотел бы применить метод fly без его реализации, тогда я бы сделал это чистым абстрактным классом.

Если бы я хотел определить тип Flies, я бы сделал его интерфейсом по методу fly.

Bird способ реализации Flies.

Я не прав?

EDIT:

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

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

+0

+1 - хороший вопрос, и я думаю, что в грядущих ответах на использование абстрактных классов будет много разумных соображений. –

+3

Просто набирайте * часть * вашего вопроса (таким образом, не отправляя * ответ *): Я бы не сказал, что интерфейсы всегда * глаголы * вообще. Интерфейсы используются * lot *, чтобы позволить классу показать лицо миру, которое лучше всего моделируется как существительное. Просто посмотрите на некоторые из интерфейсов в 'java.util':' Comparator', 'Enumeration',' List', 'Iterator',' Map', ... –

+1

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

ответ

6

Помимо вашего первого исправления i.e некоторые требования к будущему. Один из возможных вариантов использования может объявить константу и инициализировать ее в абстрактном классе.

import java.util.ArrayList; 
import java.util.List; 


public abstract class AbstractPure implements ISomeInterface { 
    public static final List<String> days = new ArrayList<String>(); 
    static{ 
     days.add("Monday"); 
     days.add("Tuesday"); 
     days.add("Wednesday");  
     days.add("Thursday"); 
     days.add("Friday"); 
     days.add("Saturday"); 
     days.add("Sunday"); 
    } 
} 
+1

Очень хорошая точка! – sji

+6

Технически это уже не чистый абстрактный класс ... – zmbq

+1

Лично я считаю, что константы в интерфейсах часто являются проблемой дизайна - по крайней мере, все, что невозможно обработать примитивами и перечислениями. Но это верный факт, что это невозможно с интерфейсами. – Voo

1

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

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

Однако я никогда не сталкивался с необходимостью чистого абстрактного класса в C#, так что это может быть гипотетической проблемой.

+0

Я исхожу из фона C++, что может повлиять на мое размышление об этом, и снова я расширил этот вопрос, чтобы проиллюстрировать потенциальную потребность в абстрактном базовом классе. – sji

+1

Да, но как вы можете определить, какой интерфейс внезапно придется есть? – zmbq

0

Я бы сказал, что оба интерфейса и классы определяют объекты. Как вы сами говорили, глаголы идут на методы - они являются свойствами этих объектов. В вашем примере fly я объявлю интерфейс FlyingCreature и определим способ летать в нем (таким образом, у вас есть такие интерфейсы, как Comparable и Serializable не Serialize и Compare. У вас есть метод compareTo). Также о вашем другом примере - птица: если у вас нет никакой логики для птицы, тогда вы объявляете ее как интерфейс.

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

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

+0

Я расширил свой вопрос, чтобы указать на потенциальный недостаток создания интерфейса для птицы. – sji

10

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

abstract class/interface Foo { 
    void foo(); 
} 

Если мы используем интерфейс теперь мы знаем наверняка, что нет никакого способа добавить дополнительные функции для Foo. Это может привести к таким вещам, как interface Foo2 implements Foo.

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

Обратите внимание, что Java8 позволит Interfaces делать в основном одно и то же - это будет полезно для библиотек, которые хотят обновить свои библиотеки, чтобы использовать lambdas, не нарушая при этом совместимость с миллионами строк кода, уже написанных.

+0

Это единственная причина, о которой я могу думать. Чтобы принять другую сторону аргумента: как вы знаете, когда что-то никогда не потребует дополнительных реализованных функций? Когда что-то определенно является интерфейсом? Должен ли я никогда не использовать интерфейс для боязни, мне может понадобиться добавить к нему некоторые функции? – sji

+0

@sji В конце концов, вызов суда зависит от фактического бизнес-кейса, поэтому, кроме очевидного, я не вижу многого, что может помочь нам там вообще. По крайней мере, на Java существует также тот факт, что множественного наследования нет. С Java8, позволяющим интерфейсам иметь стандартные реализации методов, должен пройти долгий путь, чтобы сделать это более четким. – Voo

0

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

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

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

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

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

0

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

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

Если вам просто нужно что-то вроде «флаера», тогда вы сделаете этот интерфейс, потому что птицы и самолеты и другие вещи могут реализовать интерфейс, но его единственное свойство, которое они имеют вместе.

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

Смежные вопросы