Есть ли в интерфейсе нечто большее, чем правильные методы - PullRequest
157 голосов
/ 03 февраля 2009

Допустим, у меня есть этот интерфейс:

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so on
}

И у меня есть класс, который реализует это:

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

Если я хочу использовать интерфейс IBox, я не могу создать его экземпляр, например:

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

право? Так что я бы на самом деле должен был сделать это:

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

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

Ответы [ 17 ]

3 голосов
/ 03 февраля 2009

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

Это становится немного понятнее, если интерфейсы названы -able . например, * +1008 *

public interface Saveable {
....

public interface Printable {
....

и т.д.. (Схемы именования не всегда работают, например, я не уверен, что Boxable здесь уместно)

3 голосов
/ 03 февраля 2009

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

Кроме того, я обычно призываю людей не следовать механизму "IRealname" для именования интерфейсов. Это вещь для Windows / COM, которая ставит одну ногу в могилу венгерской нотации и на самом деле не нужна (Java уже строго типизирована, и весь смысл наличия интерфейсов состоит в том, чтобы они были как можно более неотличимы от типов классов).

3 голосов
/ 05 марта 2016

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

Я обновляю ответ новыми функциями интерфейса, которые появились в версии java 8 .

Со страницы документации Oracle на Сводка интерфейса :

Объявление интерфейса может содержать

  1. метод подписи
  2. методы по умолчанию
  3. статические методы
  4. постоянные определения.

Единственными методами, которые имеют реализации, являются стандартные и статические методы.

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

  1. Чтобы определить контракт
  2. Связать несвязанные классы с возможностями (например, классы, реализующие интерфейс Serializable, могут иметь или не иметь какое-либо отношение между ними, кроме реализации этого интерфейса
  3. Для обеспечения взаимозаменяемой реализации например. шаблон стратегии
  4. Методы по умолчанию позволяют добавлять новые функциональные возможности к интерфейсам ваших библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов
  5. Организация вспомогательных методов в ваших библиотеках с помощью статических методов (статические методы можно сохранять специфичными для интерфейса в том же интерфейсе, а не в отдельном классе)

Некоторые связанные вопросы SE относительно различий между abstract class и interface и примерами использования с рабочими примерами:

В чем разница между интерфейсом и абстрактным классом?

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

Загляните на страницу документации , чтобы понять новые функции, добавленные в java 8: стандартные методы и статические методы .

2 голосов
/ 04 февраля 2009

Назначение интерфейсов - абстракция , или отделение от реализации.

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

1 голос
/ 03 февраля 2009

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

1 голос
/ 03 февраля 2009

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

множественное наследование опасно, потому что у вас может быть класс, подобный следующему:


class Box{
    public int getSize(){
       return 0;
    }
    public int getArea(){
       return 1;
    }

}

class Triangle{
    public int getSize(){
       return 1;
    }
    public int getArea(){
       return 0;
    }

}

class FunckyFigure extends Box, Triable{
   // we do not implement the methods we will used the inherited ones
}

Какой метод должен вызываться при использовании


   FunckyFigure.GetArea(); 

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

0 голосов
/ 22 июня 2018

Вот мое понимание преимуществ интерфейса. Поправь меня, если я ошибаюсь. Представьте, что мы разрабатываем ОС, а другая команда разрабатывает драйверы для некоторых устройств. Поэтому мы разработали интерфейс StorageDevice. У нас есть две его реализации (FDD и HDD), предоставленные другими разработчиками.

Затем у нас есть класс OperatingSystem, который может вызывать методы интерфейса, такие как saveData, просто передавая экземпляр класса, реализованный интерфейс StorageDevice.

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

package mypack;

interface StorageDevice {
    void saveData (String data);
}


class FDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to floppy drive! Data: "+data);
    }
}

class HDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to hard disk drive! Data: "+data);
    }
}

class OperatingSystem {
    public String name;
    StorageDevice[] devices;
    public OperatingSystem(String name, StorageDevice[] devices) {

        this.name = name;
        this.devices = devices.clone();

        System.out.println("Running OS " + this.name);
        System.out.println("List with storage devices available:");
        for (StorageDevice s: devices) {
            System.out.println(s);
        }

    }

    public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
        storage.saveData(data);
    }
}

public class Main {

    public static void main(String[] args) {

        StorageDevice fdd0 = new FDD();
        StorageDevice hdd0 = new HDD();     
        StorageDevice[] devs = {fdd0, hdd0};        
        OperatingSystem os = new OperatingSystem("Linux", devs);
        os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");    
    }
}
...