¿Por qué debería declarar una clase como una clase abstracta?

40

Conozco la sintaxis, las reglas aplicadas a la clase abstracta y quiero saber el uso de una clase abstracta.

La clase abstracta no puede ser instanciada directamente pero puede ser extendida por otra clase

¿Cuál es la ventaja de hacerlo?

¿Cómo es diferente de una interfaz?

Sé que una clase puede implementar múltiples interfaces pero solo puede extender una clase abstracta. ¿Es esa la única diferencia entre una interfaz y una clase abstracta?

Soy consciente del uso de una interfaz. Lo aprendí del modelo de delegación de eventos de AWT en Java.

¿En qué situaciones debo declarar la clase como una clase abstracta? ¿Cuáles son los beneficios de eso?

Vaibhav Jani
fuente
14
Esto ha sido preguntado, ya sabes. Una búsqueda arrojará otras preguntas como esta. Debes comenzar en Google, lo que te llevará a Stack Overflow. Todos estos son duplicados: stackoverflow.com/search?q=abstract+interface .
S.Lott
1
"uso de la clase abstracta que solo discuten ... reglas". ¿Qué? ¿Qué es diferente entre "reglas" y "uso"? Su pregunta exacta fue hecha, por cierto. Lo sé. Yo le respondí. Seguir mirando. Es importante aprender a usar la búsqueda.
S.Lott
Quiero decir "¿En qué situaciones debo declarar la clase como clase abstracta? ¿Cuáles son los beneficios de eso?"
Vaibhav Jani
Una interfaz es una clase abstracta pura, eso es todo. Ellos son uno en lo mismo. Uso la clase abstracta todo el tiempo para una función en la clase base que no se puede implementar porque necesita datos que solo tienen las subclases, pero quiero asegurarme de que cada subclase tenga esta función y la implemente en consecuencia.
AngryBird
El patrón de método de plantilla me parece muy poderoso y un buen caso de uso para las clases abstractas.
m3th0dman

Respuestas:

49

Esta respuesta hace un buen trabajo al explicar las diferencias entre una clase abstracta y una interfaz, pero no responde por qué debería declarar una.

Desde un punto de vista puramente técnico, nunca existe el requisito de declarar una clase como abstracta.

Considere las siguientes tres clases:

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

Usted no tiene que hacer la clase de base de datos abstracto, a pesar de que existe un problema evidente con su aplicación: Al escribir este programa, puede escribir new Database()y sería válido, pero que nunca funcionaría.

De todos modos, aún obtendría polimorfismo, por lo que mientras su programa solo tenga instancias SqlDatabasey OracleDatabaseejemplos, podría escribir métodos como:

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

Las clases abstractas mejoran la situación al evitar que un desarrollador cree instancias de la clase base, porque un desarrollador la ha marcado como faltante de funcionalidad . También proporciona seguridad en tiempo de compilación para que pueda asegurarse de que cualquier clase que amplíe su clase abstracta brinde la funcionalidad mínima básica para trabajar, y no tenga que preocuparse por poner métodos de código auxiliar (como el anterior) que los herederos de alguna manera tienen para saber mágicamente que tienen que anular un método para que funcione.

Las interfaces son un tema totalmente separado. Una interfaz le permite describir qué operaciones se pueden realizar en un objeto. Normalmente usaría interfaces al escribir métodos, componentes, etc. que usan los servicios de otros componentes, objetos, pero no le importa cuál es el tipo real de objeto del que obtiene los servicios.

Considere el siguiente método:

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

No le importa si el databaseobjeto hereda de un objeto en particular, solo le importa que tenga un addProductmétodo. Entonces, en este caso, una interfaz es más adecuada que hacer que todas sus clases hereden de la misma clase base.

A veces la combinación de los dos funciona muy bien. Por ejemplo:

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 cómo algunas de las bases de datos heredan de RemoteDatabase para compartir alguna funcionalidad (como conectarse antes de escribir una fila), pero FileDatabase es una clase separada que solo se implementa IProductDatabase.

Kevin McCormick
fuente
16

Similitudes

Se requieren clases e interfaces abstractas para la abstracción. No se pueden crear instancias con una nueva , pero se pueden resolver mediante la inversión de contenedores de control o mediante patrones de fábrica.

Diferencia

  1. Interfaces

    • Definir contratos públicos bien conocidos, habilidades del tipo
    • Aplicable para mostrar herencia horizontal, es decir, ramificación en el primer nivel de herencia (por ejemplo, ILog para definir facilidades de registro a la base de datos, archivo de texto, XML, SOAP, etc.)
    • Todos los miembros son públicos.
    • No se permite la implementación
    • La herencia secundaria puede tener muchas interfaces para implementar
    • Útil para la integración de terceros.
    • El nombramiento generalmente comienza con I
  2. Clase abstracta

    • Definir estructura, identidad y algunos comportamientos soportados por defecto.
    • Aplicable para mostrar herencia vertical, es decir, ramificación profunda en varios niveles (por ejemplo, clase AbstractEntity en desarrollo dirigido por dominio)
    • Los miembros pueden tener una visibilidad diferente (de público a privado)
    • Puede implementar algunos miembros (por ejemplo, * clases de lector)
    • El hijo de herencia solo puede tener una clase abstracta base

En realidad, es fácil encontrar la respuesta mediante una simple consulta de Google .

oleksii
fuente
¿Qué mena por implementación no permitida? La clase Java puede implementar interfaces.
Sajuuk
@Sajuuk esa línea se refiere a una interfaz. No puede poner la implementación de un contrato en una interfaz. Es posible que tenga una implementación predeterminada de un contrato en una clase abstracta.
oleksii
11

¿Cómo es diferente de una interfaz?

En una clase abstracta, puede implementar algunos métodos y dejar (forzar) que el resto sea implementado por la clase extendida. No puede implementar métodos en una interfaz. No puede obligar a nadie a anular nada al extender una clase ordinaria. Con una clase abstracta, puedes.

Joonas Pulakka
fuente
Esto realmente necesita una actualización para Java 8, donde se introdujeron los métodos predeterminados.
Haakon Løtveit
8

Las clases abstractas son para relaciones "es un" y las interfaces son para "puede hacer".

Las clases abstractas le permiten agregar un comportamiento base para que los programadores no tengan que codificar todo, mientras los obligan a seguir su diseño.

Tulains Córdova
fuente
3

Además de los detalles técnicos profundos, como la implementación de algunos métodos para clases abstractas, etc., el significado es así:

Las interfaces definen la capacidad común: IEnumerable define que la clase que implementa esta interfaz se puede enumerar. No dice nada sobre la clase en sí.

Las clases abstractas (o básicas) definen el comportamiento: WebRequest define un comportamiento común de todas las clases secundarias como HttpWebRequest, etc. Define el significado central de la clase y su propósito real: acceder a los recursos web.

Soleado
fuente
2

Entrada de Wikipedia .

Las principales diferencias entre una interfaz y una clase abstracta es que una clase abstracta puede proporcionar métodos implementados. Con las interfaces solo puede declarar métodos, escriba su firma. Aquí hay un ejemplo de una clase que extiende una clase abstracta que implementa dos 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";
  }
}

En este ejemplo, MyAbstractClass proporciona un método público que imprime los tres valores. En ImpClass , debe implementar getValue1 y getValue2 respectivamente desde MyInterface1 y MyInterface2 y getValue3 desde la clase abstracta.

Voilà.

Hay más aspectos (interfaz: solo métodos públicos, clase abstracta: resumen protegido y métodos abstractos públicos) pero puede leerlo usted mismo.

En una nota final, una clase abstracta que solo proporciona métodos abstractos es una clase base abstracta "pura", también conocida como una interfaz.

Jalayn
fuente
2
  • Interfaz: cuando algunas clases comparten una API (nombres de métodos y parámetros)
  • Clase abstracta: cuando algunas clases comparten el mismo código (implementación)

En otras palabras, debe comenzar con una pregunta: "¿estas clases necesariamente comparten la implementación , o simplemente tienen una interfaz común ?"

Si la respuesta es mixta, por ejemplo, estas tres clases deben compartir la implementación, pero estas otras dos solo comparten su API, entonces puede hacer una interfaz para los cinco y una clase abstracta para los tres con el común código.

También hay otras formas de compartir la implementación, por ejemplo, para encapsular un objeto con esa implementación (por ejemplo, en el patrón de Estrategia ).

Viliam Búr
fuente
1

Declararía un resumen de clase cuando no desee que el desarrollador (probablemente usted mismo) pueda instanciarlo, porque no funcionaría o no tendría sentido.

Por ejemplo, considere un juego donde hay diferentes tipos de entidades de juego. Todos ellos heredan de la GameEntityclase base .

abstract class GameEntity{

    int lifePoint, speed, damage;

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

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

    // etc...

}

Esta clase se declara abstractya que no tendría sentido instanciarla. Declara algunas acciones para las entidades del juego y algunos atributos, pero en ninguna parte de esta clase se inicializan estos atributos. Esta clase sirve como plantilla para las entidades del juego, pero no está destinada a ser instanciada por sí misma, y ​​como tal declarada abstract.

En cuanto a la diferencia de uso entre una clase abstracta y una interfaz:

A mi entender, una interfaz es una forma de obtener un comportamiento polimórfico sin estar limitada por el mecanismo de herencia única de algunos idiomas.

Volvamos al juego como ejemplo. Considere una clase Enemyque se deriva de GameEntity. Esta clase tiene un método attackMeFromDistance(RangedAttacker attacker). Este método está destinado a permitir que las entidades ataquen al enemigo desde lejos.

Como puede ver, este método toma un RangedAttackertipo como parámetro. Sin embargo, todas las entidades del juego ya heredan de GameEntity. No pueden extender otra clase.

Toma las clases Magey Archerpor ejemplo. Queremos permitir que ambos sean aceptados como parámetros en el attackMeFromDistance(RangedAttacker attacker)método, pero ya se derivan de ellos GameEntity.

Para resolver esto, creamos una nueva interfaz:

interface RangedAttacker{
    public void attackFromDistance();
}

Una clase que implementa esta interfaz debe implementar el attackFromDistance()método y, por lo tanto, se garantiza que tiene capacidades de ataque a distancia. Esto significa que el attackMeFromDistancemétodo ahora puede aceptar con seguridad las clases que implementan esta interfaz. Entonces, hacer Magee Archerimplementar esa interfaz resuelve nuestro problema.

Para mí, este es el poder de las interfaces.

Para resumir, generalmente usaría una clase abstracta cuando desee tener una clase base para algunas clases, pero no tendría sentido instanciarla por sí misma (o en el caso de que tenga abstractmétodos, eso tiene que ser implementado por las subclases, y en este caso el compilador lo obligaría a hacer la clase abstract). Usaría una interfaz para obtener un comportamiento polimórfico sin estar limitado por el mecanismo de herencia única.

Aviv Cohn
fuente
0
  1. Existe la posibilidad de que muy pocos métodos sean comunes a alguna clase (lógica de negocios). Y los métodos restantes son diferentes. En ese tipo de escenarios, puede implementar todos los métodos comunes en una clase y declarar el resto como abstracto. Entonces deberías declarar la clase como abstracta.
  2. A veces no permite crear el objeto a la clase directamente. Ese tipo de clase necesita declarar la clase como abstracta.
Dharani Kumar
fuente