Путаница с интерфейсами и абстрактными классами в Java с примерами

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

Создание фигур кажется популярной отправной точкой. Допустим, нам нужен способ моделирования 2D-фигур. Мы знаем, что каждая фигура будет иметь площадь. В чем будет разница между следующими двумя реализациями:

с интерфейсами:

public interface Shape {
    public double area();
}

public class Square implements Shape{
    private int length = 5;
    public Square(){...}

    public double area()
         return length * length;
    }
}

с абстрактным классом:

abstract class Shape {
    abstract public double area();
}

public class Square extends Shape {
    private length = 5;
    public Square(){...}

    public double area(){
        return length * length;
    }

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

Но теперь скажем, что мы хотим описать различные типы треугольников. У нас могут быть равнобедренные, острые и прямоугольные треугольники. Для меня имеет смысл использовать наследование классов в этом случае. Использование «IS-A»; определение: Прямоугольный треугольник "IS-A" Треугольник. Треугольник "IS-A" Shape. Кроме того, абстрактный класс должен определять поведение и атрибуты, которые являются общими для всех подклассов, так что это идеально:

с абстрактным классом

abstract Triangle extends Shape {
    private final int sides = 3;
}
class RightTriangle extends Triangle {
    private int base = 4;
    private int height = 5;

    public RightTriangle(){...}

    public double area() {
        return .5 * base * height
    }
}

Мы можем сделать это и с интерфейсами, с интерфейсами Triangle и Shape. Однако в отличие от наследования классов (используя отношение «IS-A» для определения того, каким должен быть подкласс), я не уверен, как использовать интерфейс. Я вижу два пути:

Первый способ:

  public interface Triangle {
      public final int sides = 3;
  }
  public class RightTriangle implements Triangle, Shape {
      private int base = 4;
      private int height = 5;

      public RightTriangle(){}
      public double area(){
          return .5 * height * base;
      }
  }

Второй способ:

public interface Triangle extends Shape {
     public final int sides = 3;
} 
public class RightTriangle implements Triangle {
    ....

    public double area(){
         return .5 * height * base;
    }
}

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

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

Кроме того, чтобы создать запутанный интерфейс, расширяющий другой интерфейс: Когда следует «IS-A»; Отношения должны игнорироваться при принятии решения о том, каким должен быть интерфейс? Возьмите этот пример:ССЫЛКА НА САЙТ.

Почему «VeryBadVampire»? быть классом и «вампиром»; быть интерфейсом? A 'VeryBadVampire' IS-A 'Vampire', так что я понимаю, что 'Vampire' должен быть суперклассом (возможно, абстрактным классом). «Вампир» класс может реализовать «смертельный» сохранить его смертоносное поведение. Кроме того, «вампир»; IS-A 'Monster', так же 'Monster' должен быть классом. «Вампир» Класс также может реализовывать интерфейс под названием «Опасный». сохранить свое опасное поведение. Если мы хотим создать нового монстра под названием «BigRat» что опасно, но не смертельно, тогда мы можем создать «BigRat»; класс, который расширяет «Monster» и реализует «Опасный».

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

Даже если вы хотите, чтобы монстр разделял вампирическое поведение, всегда можно переопределить способ представления объектов. Если бы мы хотели новый тип вампирских монстров под названием «VeryMildVampire» и мы хотели создать похожего на вампира монстра под названием «Chupacabra», мы можем сделать это:

& APOS; Вампир & APOS; класс расширяет "Monster" реализует «Опасный», «Смертельный», «BloodSuckable».
& APOS; VeryMildVampire & APOS; класс расширяет «вампир» учебный класс
& APOS; Чупакабра & APOS; класс расширяет "Monster" реализует "BloodSuckable"

Но мы также можем сделать это:

& APOS; VeryMildVampire & APOS; расширяет "монстр" реализует Опасный, Смертельный, Вампирический
& APOS; Чупакабра & APOS; расширяет "монстр" реализует Опасный, Вампирический

Второй способ здесь создает «Vampiric». интерфейс, так что мы можем более легко определить связанного монстра, а не создавать группу интерфейсов, которые определяют поведение вампира (как в первом примере). Но это нарушает отношения IS-A. Так что я в замешательстве ...

Ответы на вопрос(7)

Ваш ответ на вопрос