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

Когда нужно реализовать интерфейс и когда расширять суперкласс?

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

Итак, когда вы реализуете интерфейс и когда вы расширяете суперкласс?

4b9b3361

Ответ 1

Используйте интерфейс, если вы хотите определить контракт. То есть X должен принять Y и вернуть Z. Неважно, как это делает код. Класс может реализовывать несколько интерфейсов.

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

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

Ответ 2

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

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

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

Ответ 3

Используйте интерфейс для определения поведения. Пользовательские (абстрактные) классы (и подклассы) для реализации. Они не являются взаимоисключающими; они могут работать вместе.

Например, скажем, вы определяете объект доступа к данным. Вы хотите, чтобы ваш DAO мог загружать данные. Таким образом, установите способ загрузки на интерфейс. Это означает, что все, что хочет назвать себя DAO, должно реализовать нагрузку. Теперь давайте скажем, что вам нужно загрузить A и B. Вы можете создать общий абстрактный класс, который параметризуется (generics), чтобы предоставить схему работы загрузки. Затем вы подклассифицируете этот абстрактный класс, чтобы обеспечить конкретные реализации для A и B.

Ответ 4

Никто?

http://mindprod.com/jgloss/interfacevsabstract.html

EDIT: я должен предоставить больше, чем ссылку

Вот ситуация. Чтобы опираться на приведенный ниже пример автомобиля, рассмотрите этот

interface Drivable {
    void drive(float miles);
}

abstract class Car implements Drivable { 
    float gallonsOfGas;
    float odometer;
    final float mpg;
    protected Car(float mpg) { gallonsOfGas = 0; odometer = 0; this.mpg = mpg; }
    public void addGas(float gallons) { gallonsOfGas += gallons; }
    public void drive(float miles) { 
        if(miles/mpg > gallonsOfGas) throw new NotEnoughGasException();
        gallonsOfGas -= miles/mpg;
        odometer += miles;
    }
}

class LeakyCar extends Car { // still implements Drivable because of Car
    public addGas(float gallons) { super.addGas(gallons * .8); } // leaky tank
}

class ElectricCar extends Car {
    float electricMiles;
    public void drive(float miles) { // can we drive the whole way electric?
         if(electricMiles > miles) {
             electricMiles -= miles;
             odometer += miles;
             return;                 // early return here
         }
         if(electricMiles > 0) { // exhaust electric miles first
             if((miles-electricMiles)/mpg > gallonsOfGas) 
                 throw new NotEnoughGasException();
             miles -= electricMiles;
             odometer += electricMiles;
             electricMiles = 0;
         }
         // finish driving
         super.drive(miles);
    }
}

Ответ 5

Основная причина использования абстрактных классов и интерфейсов различна.

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

Это может быть плохой пример, но наиболее очевидное использование абстрактных классов в структуре Java находится в пределах классов java.io. OutputStream - это просто поток байтов. Там, где этот поток идет, полностью зависит от того, какой подкласс OutputStream вы используете... FileOutputStream, PipedOutputStream, поток вывода, созданный с помощью метода java.net.Socket getOutputStream...

Примечание. java.io также использует шаблон Decorator для обтекания потоков в других потоках/читателях/писателях.

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

Наиболее очевидное использование интерфейсов находится в рамках коллекции.

Мне все равно, как List добавляет/удаляет элементы, пока я могу вызвать add(something) и get(0) для размещения и получения элементов. Он может использовать массив (ArrayList, CopyOnWriteArrayList), связанный список (LinkedList) и т.д.

Другим преимуществом использования интерфейсов является то, что класс может реализовать более одного. LinkedList представляет собой реализацию как List , так и Deque.

Ответ 6

Одним из способов выбора между interface и a base class является рассмотрение права собственности на код. Если вы контролируете весь код, базовый класс является жизнеспособным вариантом. Если, с другой стороны, многие разные компании могут захотеть создать сменные компоненты, то есть определить контракт, тогда ваш единственный выбор - это интерфейс.

Ответ 7

Я нашел несколько статей, особенно тех, кто описывает, почему вы не должны использовать наследование реализации (например, суперклассы):

Ответ 8

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

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

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

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

Ответ 9

Вы можете думать о расширении от суперкласса, если производный класс имеет тот же тип. Я имею в виду, что когда класс расширяет абстрактный класс, они оба должны быть одного типа, с той лишь разницей, что суперкласс имеет более общее поведение, а подкласс имеет более конкретное поведение. Интерфейс - совершенно другая концепция. Когда класс реализует интерфейс, его либо выставлять некоторый API (контракт), либо получать определенное поведение. Чтобы привести пример, я бы сказал, что Car является абстрактным классом. Вы можете расширить многие классы от него, как говорят Ford, Chevy и т.д., Которые являются каждым из автомобилей типа. Но тогда, если вам нужно определенное конкретное поведение, например, скажем, вам нужен GPS в автомобиле, тогда конкретный класс, например Ford, должен использовать интерфейс GPS.

Ответ 10

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

Ответ 11

Думаю, я приведу пример классической машины.

Когда у вас есть интерфейс автомобиля, вы можете создать Ford, Chevy и Oldsmobile. Другими словами, вы создаете различные виды автомобилей из интерфейса автомобиля.

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