Por que devo declarar uma classe como abstrata?


40

Conheço a sintaxe, as regras aplicadas à classe abstrata e quero saber o uso de uma classe abstrata

A classe abstrata não pode ser instanciada diretamente, mas pode ser estendida por outra classe

Qual é a vantagem de fazer isso?

Como é diferente de uma interface?

Eu sei que uma classe pode implementar várias interfaces, mas só pode estender uma classe abstrata. Essa é a única diferença entre uma interface e uma classe abstrata?

Estou ciente do uso de uma interface. Aprendi isso com o modelo de delegação de eventos do AWT em Java.

Em quais situações devo declarar classe como uma classe abstrata? Quais são os benefícios disso?


14
Isso foi perguntado, você sabe. Uma pesquisa mostrará outras perguntas como esta. Você deve começar no Google, o que levará ao Stack Overflow. Todos estes são duplicados: stackoverflow.com/search?q=abstract+interface .
31511 S.Lott

11
"uso da classe Abstract eles apenas discutem ... regras". O que? O que há de diferente entre "regras" e "uso"? Sua pergunta exata foi feita, a propósito. Eu sei. Eu atendi. Continue olhando. É importante aprender a usar a pesquisa.
31511 S.Lott

Quero dizer "Em quais situações devo declarar classe como classe abstrata? Quais são os benefícios disso?"
21411 Vaibhav Jani

Uma interface é uma classe abstrata pura, só isso. Eles são um no mesmo. Uso classe abstrata o tempo todo para uma função na classe base que não pode ser implementada porque precisa de dados que apenas as subclasses possuem, mas quero garantir que todas as subclasses tenham essa função e a implementem de acordo.
AngryBird 29/07

Acho o padrão do método template muito poderoso e um bom caso de uso para classes abstratas.
M3th0dman

Respostas:


49

Essa resposta explica bem as diferenças entre uma classe abstrata e uma interface, mas não responde por que você deve declarar uma.

Do ponto de vista puramente técnico, nunca há a exigência de declarar uma classe como abstrata.

Considere as três classes a seguir:

class Database { 
    public String[] getTableNames() { return null; } //or throw an exception? who knows...
}

class SqlDatabase extends Database { } //TODO: override getTableNames

class OracleDatabase extends Database { }  //TODO: override getTableNames

Você não precisa abstrair a classe Database, mesmo que exista um problema óbvio com a sua implementação: Ao escrever este programa, você poderia digitar new Database()e seria válido, mas nunca funcionaria.

Independentemente disso, você ainda obteria polimorfismo; portanto, enquanto seu programa apenas cria SqlDatabasee OracleDatabaseinstâncias, você pode escrever métodos como:

public void printTableNames(Database database) {
    String[] names = database.getTableNames();
}

As classes abstratas melhoram a situação impedindo que um desenvolvedor instancie a classe base, porque um desenvolvedor a marcou como tendo falta de funcionalidade . Ele também fornece segurança em tempo de compilação, para que você possa garantir que todas as classes que estendem sua classe abstrata forneçam a funcionalidade mínima necessária para o trabalho e não precise se preocupar em colocar métodos stub (como o acima) que os herdeiros de alguma forma tenham saber magicamente que eles precisam substituir um método para fazê-lo funcionar.

As interfaces são um tópico totalmente separado. Uma interface permite descrever quais operações podem ser executadas em um objeto. Você normalmente usaria interfaces ao escrever métodos, componentes etc. que usam os serviços de outros componentes, objetos, mas não se importa com o tipo de objeto real do qual está obtendo os serviços.

Considere o seguinte método:

public void saveToDatabase(IProductDatabase database) {
     database.addProduct(this.getName(), this.getPrice());
}

Você não se importa se o databaseobjeto é herdado de um objeto em particular, apenas se importa que ele tenha um addProductmétodo. Portanto, nesse caso, uma interface é mais adequada do que fazer com que todas as suas classes sejam herdadas da mesma classe base.

Às vezes, a combinação dos dois funciona muito bem. Por exemplo:

abstract class RemoteDatabase implements IProductDatabase { 
    public abstract String[] connect();
    public abstract void writeRow(string col1, string col2);

    public void addProduct(String name, Double price) {
        connect();
        writeRow(name, price.toString());
    }
}

class SqlDatabase extends RemoteDatabase {
    //TODO override connect and writeRow
}

class OracleDatabase extends RemoteDatabase { 
    //TODO override connect and writeRow
}

class FileDatabase implements IProductDatabase {
    public void addProduct(String name, Double price) {
         //TODO: just write to file
    }
}

Observe como alguns dos bancos de dados herdam do RemoteDatabase para compartilhar algumas funcionalidades (como conectar antes de escrever uma linha), mas o FileDatabase é uma classe separada que apenas implementa IProductDatabase.


16

Semelhanças

Classes abstratas e interfaces são necessárias para a abstração. Eles não podem ser instanciados com um novo , mas podem ser resolvidos na inversão de contêineres de controle ou através de padrões de fábrica.

Diferença

  1. Interfaces

    • Definir contratos públicos conhecidos, habilidades do tipo
    • Aplicável para mostrar herança horizontal, ou seja, ramificação no primeiro nível de herança (por exemplo, ILog para definir recursos de registro em banco de dados, arquivo de texto, XML, SOAP etc.)
    • Todos os membros são públicos
    • Nenhuma implementação permitida
    • O filho da herança pode ter muitas interfaces para implementar
    • Útil para integração de terceiros
    • A nomeação geralmente começa com I
  2. Classe abstrata

    • Definir estrutura, identidade e algum comportamento padrão suportado
    • Aplicável para mostrar herança vertical, ou seja, ramificação profunda nos vários níveis (por exemplo, classe AbstractEntity no desenvolvimento orientado a domínio)
    • Os membros podem ter visibilidade diferente (de pública a privada)
    • Você pode implementar alguns membros (por exemplo, * classes de leitor)
    • O filho da herança pode ter apenas uma classe abstrata base

Na verdade, é fácil encontrar a resposta através de uma simples consulta no Google .


o que você mena por implementação não permitido? classe java pode implementar interfaces.
Sajuuk 5/07

@Sajuuk essa linha se refere a uma interface. Você não pode colocar a implementação de um contrato em uma interface. Você pode ter a implementação padrão de um contrato em uma classe abstrata.
Oleksii

11

Como é diferente de uma interface?

Em uma classe abstrata, você pode implementar alguns métodos e deixar (forçar) o restante a ser implementado pela classe de extensão. Você não pode implementar métodos em uma interface. Você não pode forçar ninguém a substituir nada ao estender uma classe comum. Com uma classe abstrata, você pode.


Isso realmente precisa de uma atualização para o Java 8, onde os métodos padrão foram introduzidos.
Haakon Løtveit

8

As classes abstratas são para relacionamentos "is a" e as interfaces são para "pode ​​fazer".

As classes abstratas permitem adicionar o comportamento base para que os programadores não precisem codificar tudo, enquanto os forçam a seguir seu design.


3

Além dos detalhes técnicos, como a implementação de alguns métodos para classes abstratas, etc., o significado é o seguinte:

Interfaces definem capacidade comum - IEnumerable define que a classe que implementa essa interface pode ser enumerada. Não diz nada sobre a classe em si.

As classes abstratas (ou básicas) definem o comportamento - o WebRequest define um comportamento comum de todas as classes filho, como HttpWebRequest, etc. Ele define o significado principal da classe e seu objetivo real - acessar recursos da Web.


2

Entrada da Wikipedia .

As principais diferenças entre uma interface e uma classe abstrata é que uma classe abstrata pode fornecer métodos implementados. Com interfaces, você só pode declarar métodos, escreva sua assinatura. Aqui está um exemplo de uma classe que estende uma classe abstrata que implementa duas interfaces: (java)

interface MyInterface1 {
  string getValue1();
}

interface MyInterface2 {
  string getValue2();
}

abstract class MyAbstractClass implements MyInterface1, MyInterface2{
  void printValues() {
    System.out.println("Value 1: " + getValue1() + ", Value 2: " + getValue2() + 
                       ", Value 3: " + getValue3());
  }

  protected abstract string getValue3();
}

class ImpClass extends MyAbstractClass {
  public string getValue1() {
    return "1";
  }

  public string getValue2() {
    return "2";
  }

  protected string getValue3() {
    return "3";
  }
}

Neste exemplo, o MyAbstractClass fornece um método público que imprime todos os três valores. No ImpClass, você precisa implementar getValue1 e getValue2, respectivamente, de MyInterface1 e MyInterface2 e getValue3 da classe abstrata.

Voilà.

Existem mais aspectos (interface: apenas métodos públicos, classe abstrata: métodos abstratos protegidos e abstratos públicos), mas você pode ler isso por si mesmo.

Em uma nota final, uma classe abstrata que apenas fornece métodos abstratos é uma classe base abstrata "pura", também conhecida como interface.


2
  • Interface - quando algumas classes compartilham uma API (nomes e parâmetros de métodos)
  • Classe abstrata - quando algumas classes compartilham o mesmo código (implementação)

Em outras palavras, você deve começar com uma pergunta: "essas classes necessariamente compartilham a implementação ou apenas têm uma interface comum ?"

Se a resposta for mista, como - essas três classes devem compartilhar a implementação, mas essas outras duas compartilham apenas sua API -, você poderá criar uma interface para todas as cinco e uma classe abstrata para as três com o mesmo código.

Também existem outras maneiras de compartilhar a implementação, por exemplo, encapsular um objeto com essa implementação (por exemplo, no padrão Estratégia ).


1

Você declararia um resumo de classe quando não quiser que o desenvolvedor (provavelmente você mesmo) possa instancia-lo, porque não funcionaria ou não faria sentido.

Por exemplo, considere um jogo em que existem diferentes tipos de entidades de jogo. Todos eles herdam da GameEntityclasse base .

abstract class GameEntity{

    int lifePoint, speed, damage;

    public attack(GameEntity target){ target.damage(damage); }

    public damage(int damageInflicted){ lifePoint -= damageInflicted - speed; }

    // etc...

}

Essa classe é declarada, abstractpois não faria sentido instancia-la. Ele declara algumas ações para as entidades do jogo e alguns atributos, mas em nenhum lugar nesta classe esses atributos são inicializados. Essa classe serve como modelo para as entidades do jogo, mas não deve ser instanciada por si própria e, como tal, declarada abstract.

Em relação à diferença de uso entre uma classe abstrata e uma interface:

A meu ver, uma interface é uma maneira de obter comportamento polimórfico sem ser limitada pelo mecanismo de herança única de algumas linguagens.

Vamos voltar ao jogo como um exemplo. Considere uma classe Enemyque é derivada GameEntity. Essa classe tem um método attackMeFromDistance(RangedAttacker attacker). Este método destina-se a permitir que as entidades atacem o inimigo de longe.

Como você pode ver, esse método usa um RangedAttackertipo como parâmetro. No entanto, todas as entidades do jogo já herdam GameEntity. Eles não podem estender outra classe.

Tome as aulas Magee, Archerpor exemplo. Queremos permitir que ambos sejam aceitos como parâmetros no attackMeFromDistance(RangedAttacker attacker)método, mas eles já são derivados GameEntity.

Para resolver isso, criamos uma nova interface:

interface RangedAttacker{
    public void attackFromDistance();
}

Uma classe que implementa essa interface deve implementar o attackFromDistance()método e, portanto, é garantido que ele variou os recursos de ataque. Isso significa que o attackMeFromDistancemétodo agora pode aceitar com segurança as classes que implementam essa interface. Portanto, criar Magee Archerimplementar essa interface resolve nosso problema.

Para mim, esse é o poder das interfaces.

Então, para resumir, você usaria uma classe abstrata quando quiser ter uma classe base para algumas classes, mas não faria sentido instancia-la por si só (ou no caso em que ela tenha abstractmétodos, isso deve ser implementado pelas subclasses e, nesse caso, o compilador o forçaria a criar a classe abstract). Você usaria uma interface para obter um comportamento polimórfico sem ser limitado pelo mecanismo de herança única.


0
  1. Há chances de que poucos métodos sejam comuns a alguma classe (lógica de negócios). E os métodos restantes são diferentes. Nesse tipo de cenário, você pode implementar todos os métodos comuns em uma classe e declarar o restante como abstrato. Então você deve declarar a classe como abstrata.
  2. Às vezes, você não permite criar o objeto diretamente para a classe. Esse tipo de classe você precisa declarar a classe como abstrata.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.