Interfaces e Conflitos de Classes Abstratas em Java com Exemplos

Estou tendo problemas para entender quando usar uma interface em oposição a uma classe abstrata e vice-versa. Além disso, estou confuso quando estender uma interface com outra interface. Desculpe pelo longo post, mas isso é muito confuso.

Criar formas parece um ponto de partida popular. Digamos que queremos uma maneira de modelar formas 2D. Sabemos que cada forma terá uma área. Qual seria a diferença entre as duas implementações a seguir:

com interfaces:

public interface Shape {
    public double area();
}

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

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

com classe abstrata:

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

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

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

Eu entendo que classes abstratas permitem que você defina variáveis ​​de instância e permite que você dê implementações de métodos, enquanto uma interface não pode fazer essas coisas. Mas neste caso, parece que estas duas implementações são idênticas. Então, usar qualquer um está bem?

Mas agora digamos que queremos descrever diferentes tipos de triângulos. Podemos ter triângulos isósceles, agudos e de ângulo reto. Para mim, faz sentido usar herança de classes nesse caso. Usando a definição 'IS-A': um triângulo retângulo "IS-A" Triangle. Uma forma triangular "IS-A". Além disso, uma classe abstrata deve definir comportamentos e atributos que são comuns em todas as subclasses, então isso é perfeito:

com aula abstrata

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
    }
}

Podemos fazer isso com interfaces também, com interfaces sendo Triangle e Shape. No entanto, diferentemente da herança de classe (usando o relacionamento 'IS-A' para definir o que deve ser uma subclasse), não sei como usar uma interface. Eu vejo duas maneiras:

Primeira maneira:

  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;
      }
  }

Segunda maneira:

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

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

Parece-me que ambas as formas funcionam. Mas quando você usaria um caminho sobre o outro? E há alguma vantagem em usar interfaces sobre classes abstratas para representar triângulos diferentes? Apesar de complicarmos a descrição de uma forma, o uso de interfaces versus classes abstratas ainda parece equivalente.

Um componente crítico para as interfaces é que ele pode definir comportamentos que podem ser compartilhados entre classes não relacionadas. Assim, uma interface Flyable estaria presente nas classes Airplane e Bird. Portanto, neste caso, é claro que uma abordagem de interface é preferida.

Além disso, para construir a interface confusa estendendo outra interface: Quando o relacionamento 'IS-A' deve ser ignorado ao decidir sobre o que deve ser uma interface? Veja este exemplo:LIGAÇÃO.

Por que 'VeryBadVampire' deve ser uma classe e 'Vampire' ser uma interface? Um 'VeryBadVampire' IS-A 'Vampiro', então meu entendimento é que um 'Vampiro' deveria ser uma superclasse (talvez uma classe abstrata). Uma classe 'Vampire' pode implementar 'letal' para manter seu comportamento letal. Além disso, um 'Vampiro' IS-A 'Monstro', então 'Monstro' também deveria ser uma classe. Uma classe 'Vampire' também pode implementar uma interface chamada 'Dangerous' para manter seu comportamento perigoso. Se quisermos criar um novo monstro chamado 'BigRat', que é perigoso, mas não letal, então podemos criar uma classe 'BigRat' que amplia 'Monster' e implementa 'Dangerous'.

O acima não alcançaria a mesma saída do uso de 'Vampire' como uma interface (descrita no link)? A única diferença que vejo é que usar herança de classe e preservar o relacionamento 'IS-A' esclarece muita confusão. No entanto, isso não é seguido. Qual é a vantagem de fazer isso?

Mesmo se você quisesse que um monstro compartilhasse o comportamento vampírico, sempre é possível redefinir como os objetos são representados. Se nós quiséssemos um novo tipo de vampiro chamado 'VeryMildVampire' e nós quiséssemos criar um vampiro chamado 'Chupacabra', nós podemos fazer isso:

A classe 'Vampiro' amplia 'Monstro' implementa 'Perigosa', 'Letal', 'Sangue de Sangue'
A classe 'VeryMildVampire' amplia a classe 'Vampire'
A aula de 'Chupacabra' amplia 'Monster' implementa 'BloodSuckable'

Mas também podemos fazer isso:

'VeryMildVampire' estende 'Monster' implementa Dangerous, Lethal, Vampiric
'Chupacabra' estende 'Monster' implementa Dangerous, Vampiric

A segunda maneira aqui cria uma interface 'Vampírica' para que possamos mais facilmente definir um monstro relacionado ao invés de criar um monte de interfaces que definem comportamentos vampíricos (como no primeiro exemplo). Mas isso quebra o relacionamento IS-A. Então estou confuso ...

questionAnswers(7)

yourAnswerToTheQuestion