Clase abstracta vs interfaz en Java


87

Me hicieron una pregunta, quería que revisaran mi respuesta aquí.

P: ¿ En qué escenario es más apropiado extender una clase abstracta en lugar de implementar la (s) interfaz (s)?

R: Si usamos el patrón de diseño del método de plantilla.

Estoy en lo correcto ?

Lamento no haber podido formular la pregunta con claridad.
Conozco la diferencia básica entre clase abstracta e interfaz.

1) use la clase abstracta cuando el requisito sea tal que necesitemos implementar la misma funcionalidad en cada subclase para una operación específica (implementar el método) y una funcionalidad diferente para algunas otras operaciones (solo firmas de métodos)

2) use la interfaz si necesita poner la firma para que sea la misma (y la implementación diferente) para que pueda cumplir con la implementación de la interfaz

3) podemos extender un máximo de una clase abstracta, pero podemos implementar más de una interfaz

Reiterando la pregunta: ¿Hay otros escenarios, además de los mencionados anteriormente, en los que específicamente requerimos usar la clase abstracta (uno es ver que el patrón de diseño del método de plantilla se basa conceptualmente solo en esto)?

Interfaz frente a clase abstracta

Elegir entre estos dos depende realmente de lo que quieras hacer, pero por suerte para nosotros, Erich Gamma puede ayudarnos un poco.

Como siempre hay una compensación, una interfaz le da libertad con respecto a la clase base, una clase abstracta le da la libertad de agregar nuevos métodos más adelante . - Erich Gamma

No puede ir y cambiar una interfaz sin tener que cambiar muchas otras cosas en su código, por lo que la única forma de evitar esto sería crear una interfaz completamente nueva, lo que podría no siempre ser algo bueno.

Abstract classesdebe usarse principalmente para objetos que están estrechamente relacionados. Interfacesson mejores para proporcionar funciones comunes para clases no relacionadas.




Esto no está duplicado. OP quiere saber cuándo extender la clase abstracta en lugar de implementar una interfaz. No quiere saber cuándo escribir una clase abstracta o una interfaz. Su clase e interfaz abstractas ya están escritas. Hd quiere saber si extender o implementar.
Shiplu Mokaddim

1
@ shiplu.mokadd.im Esa es una distinción sin diferencia. No puede utilizar una clase abstracta sin ampliarla. Su quisquilloso aquí parece completamente inútil.
Marqués de Lorne

Respuestas:


86

Cuándo utilizar interfaces

Una interfaz le permite a alguien comenzar desde cero para implementar su interfaz o implementar su interfaz en algún otro código cuyo propósito original o principal era bastante diferente de su interfaz. Para ellos, su interfaz es solo incidental, algo que deben agregar a su código para poder usar su paquete. La desventaja es que todos los métodos de la interfaz deben ser públicos. Es posible que no desee exponer todo.

Cuándo usar clases abstractas

Una clase abstracta, por el contrario, proporciona más estructura. Por lo general, define algunas implementaciones predeterminadas y proporciona algunas herramientas útiles para una implementación completa. El problema es que el código que lo usa debe usar su clase como base. Eso puede ser muy inconveniente si los otros programadores que desean usar su paquete ya han desarrollado su propia jerarquía de clases de forma independiente. En Java, una clase puede heredar de una sola clase base.

Cuándo usar ambos

Puede ofrecer lo mejor de ambos mundos, una interfaz y una clase abstracta. Los implementadores pueden ignorar su clase abstracta si así lo desean. El único inconveniente de hacer eso es llamar a métodos a través de su nombre de interfaz es un poco más lento que llamarlos a través de su nombre de clase abstracto.


Creo que OP quiere saber cuándo extender la clase abstracta en lugar de implementar una interfaz
Shiplu Mokaddim

@ shiplu.mokadd.im En realidad, el OP hizo una pregunta muy específica, a la que la respuesta es 'sí' o 'no'.
Marqués de Lorne

4
Tienes razón. Pero en SO respondemos sí / no con una explicación adecuada.
Shiplu Mokaddim

1
@ shiplu.mokadd.im No veo cómo eso le da licencia para formular mal su pregunta.
Marqués de Lorne

Solo sobre la base de esta única declaración If we are using template method design patternNo podemos decir YESoNO
DivineDesert

31

reiterando la pregunta: hay cualquier otro escenario además de los mencionados anteriormente donde específicamente requerimos usar la clase abstracta (uno es ver, el patrón de diseño del método de plantilla se basa conceptualmente en esto solo)

Sí, si usa JAXB. No le gustan las interfaces. Debería utilizar clases abstractas o solucionar esta limitación con genéricos.

A partir de un blog personal de post :

Interfaz:

  1. Una clase puede implementar múltiples interfaces
  2. Una interfaz no puede proporcionar ningún código en absoluto
  3. Una interfaz solo puede definir constantes finales estáticas públicas
  4. Una interfaz no puede definir variables de instancia
  5. Agregar un nuevo método tiene un efecto dominó en la implementación de clases (mantenimiento de diseño)
  6. JAXB no puede lidiar con interfaces
  7. Una interfaz no puede extender o implementar una clase abstracta
  8. Todos los métodos de interfaz son públicos

En general, las interfaces deben usarse para definir contratos (qué se debe lograr, no cómo lograrlo).

Clase abstracta:

  1. Una clase puede extender como máximo una clase abstracta
  2. Una clase abstracta puede contener código
  3. Una clase abstracta puede definir tanto constantes estáticas como de instancia (final)
  4. Una clase abstracta puede definir variables de instancia
  5. La modificación del código de clase abstracto existente tiene efectos dominó en la extensión de clases (mantenimiento de implementación)
  6. Agregar un nuevo método a una clase abstracta no tiene un efecto dominó en la extensión de clases
  7. Una clase abstracta puede implementar una interfaz.
  8. Las clases abstractas pueden implementar métodos privados y protegidos

Las clases abstractas deben usarse para la implementación (parcial). Pueden ser un medio para restringir la forma en que se deben implementar los contratos de API.


3
En Java 8 para la interfaz # 8, también puede tener métodos defaulty static.
Usuario novato


9

Hay muchas respuestas excelentes aquí, pero a menudo encuentro que usar AMBAS interfaces y clases abstractas es la mejor ruta. Considere este ejemplo artificial:

Eres desarrollador de software en un banco de inversión y necesitas crear un sistema que coloque pedidos en un mercado. Su interfaz de captura la idea más general de lo que un sistema de comercio hace ,

1) Trading system places orders
2) Trading system receives acknowledgements

y se puede capturar en una interfaz, ITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

Ahora los ingenieros que trabajan en el mostrador de ventas y en otras líneas comerciales pueden comenzar a interactuar con su sistema para agregar la funcionalidad de colocación de pedidos a sus aplicaciones existentes. ¡Y aún no has comenzado a construir! Este es el poder de las interfaces.

Así que continúe y construya el sistema para los comerciantes de acciones ; ¡Han escuchado que su sistema tiene una función para encontrar acciones baratas y están ansiosos por probarlo! Captura este comportamiento en un método llamado findGoodDeals(), pero también se da cuenta de que hay muchas cosas complicadas que están involucradas en la conexión a los mercados. Por ejemplo, tienes que abrir un SocketChannel,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

Las implementaciones concretas van a tener muchos de estos métodos desordenados como connectToMarket() , pero findGoodDeals()es lo único que realmente les importa a los traders.

Aquí es donde entran en juego las clases abstractas. Su jefe le informa que los comerciantes de divisas también quieren utilizar su sistema. Y al observar los mercados de divisas, se ve que las tuberías son casi idénticas a las de los mercados de valores. De hecho, connectToMarket()se puede reutilizar literalmente para conectarse a los mercados de divisas. Sin embargo, findGoodDeals()es un concepto muy diferente en el ámbito de las divisas. Entonces, antes de pasar el código base al chico mago de las divisas al otro lado del océano, primero refactoriza en unabstract clase, dejando sin findGoodDeals()implementar

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Su sistema de negociación de acciones implementa findGoodDeals() como ya lo ha definido,

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

pero ahora el genio FX puede construir su sistema simplemente proporcionando una implementación de findGoodDeals() para las divisas; ¡no tiene que volver a implementar las conexiones de socket o incluso los métodos de interfaz!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

La programación en una interfaz es poderosa, pero las aplicaciones similares a menudo vuelven a implementar métodos de formas casi idénticas. El uso de una clase abstracta evita nuevas implementaciones, al tiempo que conserva el poder de la interfaz.

Nota: uno puede preguntarse por qué findGreatDeals()no forma parte de la interfaz. Recuerde, la interfaz define los componentes más generales de un sistema comercial. Otro ingeniero puede desarrollar un sistema de comercio COMPLETAMENTE DIFERENTE, en el que no les importa encontrar buenas ofertas. La interfaz garantiza que la mesa de ventas también pueda interactuar con su sistema, por lo que es preferible no enredar su interfaz con conceptos de aplicación como "grandes ofertas".


6

¿Cuáles deberías usar, clases abstractas o interfaces?

Considere usar clases abstractas si alguna de estas declaraciones se aplica a su caso de uso:

Quieres compartir código entre varias clases estrechamente relacionadas.

Espera que las clases que amplían su clase abstracta tengan muchos métodos o campos comunes, o requieran modificadores de acceso distintos de los públicos (como protegidos y privados).

Quiere declarar campos no estáticos o no finales. Esto le permite definir métodos que pueden acceder y modificar el estado del objeto al que pertenecen.

Considere el uso de interfaces si alguna de estas declaraciones se aplica a su caso de uso:

Espera que clases no relacionadas implementen su interfaz. Por ejemplo, las interfaces Comparable y Cloneable son implementadas por muchas clases no relacionadas.

Desea especificar el comportamiento de un tipo de datos en particular, pero no le preocupa quién implementa su comportamiento.

Desea aprovechar la herencia múltiple de tipos.

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


4

Las cosas han cambiado mucho en los últimos tres años con la adición de nuevas capacidades para interactuar con la versión de Java 8.

Desde la página de documentación de Oracle en la interfaz:

Una interfaz es un tipo de referencia, similar a una clase, que solo puede contener constantes, firmas de métodos, métodos predeterminados, métodos estáticos y tipos anidados. Los cuerpos de método existen solo para métodos predeterminados y métodos estáticos.

Como citó en su pregunta, la clase abstracta se ajusta mejor al patrón de método de plantilla en el que debe crear un esqueleto. La interfaz no se puede utilizar aquí.

Una consideración más para preferir la clase abstracta sobre la interfaz:

No tiene implementación en la clase base y solo las subclases tienen que definir su propia implementación. Necesita una clase abstracta en lugar de una interfaz, ya que desea compartir el estado con las subclases.

La clase abstracta establece "es una" relación entre clases relacionadas y la interfaz proporciona "tiene una" capacidad entre clases no relacionadas .


Con respecto a la segunda parte de su pregunta, que es válida para la mayoría de los lenguajes de programación, incluido java antes del lanzamiento de java-8

Como siempre hay una compensación, una interfaz le da libertad con respecto a la clase base, una clase abstracta le da la libertad de agregar nuevos métodos más adelante. - Erich Gamma

No puede ir y cambiar una interfaz sin tener que cambiar muchas otras cosas en su código

Si prefiere la clase abstracta para interactuar antes con las dos consideraciones anteriores, debe volver a pensar ahora, ya que los métodos predeterminados han agregado capacidades poderosas a las interfaces.

Los métodos predeterminados le permiten agregar nuevas funciones a las interfaces de sus bibliotecas y garantizar la compatibilidad binaria con el código escrito para versiones anteriores de esas interfaces.

Para seleccionar uno de ellos entre interfaz y clase abstracta, la página de documentación de Oracle cita que:

Las clases abstractas son similares a las interfaces. No puede crear una instancia de ellos, y pueden contener una combinación de métodos declarados con o sin una implementación. Sin embargo, con las clases abstractas, puede declarar campos que no son estáticos y finales, y definir métodos concretos públicos, protegidos y privados.

Con las interfaces, todos los campos son automáticamente públicos, estáticos y finales, y todos los métodos que declare o defina (como métodos predeterminados) son públicos. Además, puede ampliar solo una clase, sea abstracta o no, mientras que puede implementar cualquier número de interfaces.

Consulte estas preguntas relacionadas para obtener más detalles:

Interfaz vs clase abstracta (OO general)

¿Cómo debería haber explicado la diferencia entre una interfaz y una clase abstracta?

En resumen: la balanza se inclina más hacia las interfaces ahora .

¿Hay otros escenarios, además de los mencionados anteriormente, donde específicamente requerimos usar la clase abstracta (uno es ver que el patrón de diseño del método de plantilla se basa conceptualmente solo en esto)?

Algunos patrones de diseño usan clases abstractas (sobre interfaces) además del patrón del método Template.

Patrones de creación:

Abstract_factory_pattern

Patrones estructurales:

Decorator_pattern

Patrones de comportamiento:

Mediator_pattern


Esto: "La clase abstracta establece" es una "relación entre clases relacionadas y la interfaz proporciona" tiene una "capacidad entre clases no relacionadas".
Gabriel

3

No tienes razón. Hay muchos escenarios. Simplemente no es posible reducirlo a una sola regla de 8 palabras.


1
A menos que seas vago como; Utilice una interfaz siempre que pueda;)
Peter Lawrey

@PeterLawrey Sí, no dejes que los argumentos circulares te detengan ;-)
Marqués de Lorne

Después de todo, esto es "desbordamiento de pila". ;) Mi punto es que si puede usar la interfaz más simple, hágalo. De lo contrario, no tiene más remedio que utilizar una clase abstracta. No lo veo muy complicado.
Peter Lawrey

Creo que podrías aportar una idea más constructiva. como hablar sobre algunos escenarios representativos /
Adams.H

3

La respuesta más corta es extender la clase abstracta cuando algunas de las funcionalidades que busca ya estén implementadas en ella.

Si implementa la interfaz, debe implementar todo el método. Pero para la clase abstracta, el número de métodos que necesita implementar podría ser menor.

En el patrón de diseño de la plantilla debe haber un comportamiento definido. Este comportamiento depende de otros métodos que son abstractos. Al crear una subclase y definir esos métodos, realmente define el comportamiento principal. El comportamiento subyacente no puede estar en una interfaz ya que la interfaz no define nada, solo declara. Entonces, un patrón de diseño de plantilla siempre viene con una clase abstracta. Si desea mantener intacto el flujo del comportamiento, debe extender la clase abstracta pero no anular el comportamiento principal.


La referencia adicional para la función virtual pura agregará más información sobre la convergencia de la clase abstracta y la interfaz , Pure virtual functions can also be used where the method declarations are being used to define an interface - similar to what the interface keyword in Java explicitly specifies. In such a use, derived classes will supply all implementations. In such a design pattern, the abstract class which serves as an interface will contain only pure virtual functions, but no data members or ordinary methods. parte (1/2)
Abhijeet

La parte (2/2) La divergencia de la clase abstracta y la interfaz se explica en la última línea de arriba no data members or ordinary methods[en la clase abstracta].
Abhijeet

3

En mi opinión, la diferencia básica es que an interface can't contain non abstract methods while an abstract class can . Entonces, si las subclases comparten un comportamiento común, este comportamiento puede implementarse en la superclase y, por lo tanto, heredarse en las subclases.

También cité lo siguiente del libro "Ppatterns de diseño de arquitectura de software en Java"

"En el lenguaje de programación Java no hay soporte para la herencia múltiple. Eso significa que una clase puede heredar solo de una sola clase. Por lo tanto, la herencia debe usarse solo cuando sea absolutamente necesario. Siempre que sea posible, los métodos que denotan el comportamiento común deben declararse en la forma de una interfaz Java para ser implementada por diferentes clases de implementadores. Pero las interfaces tienen la limitación de que no pueden proporcionar implementaciones de métodos. Esto significa que cada implementador de una interfaz debe implementar explícitamente todos los métodos declarados en una interfaz, incluso cuando algunos de estos Los métodos representan la parte invariable de la funcionalidad y tienen exactamente la misma implementación en todas las clases del implementador, lo que conduce a un código redundante.El siguiente ejemplo demuestra cómo el patrón Abstract Parent Class puede usarse en tales casos sin requerir implementaciones de métodos redundantes.


2

Las clases abstractas son diferentes de las interfaces en dos aspectos importantes

  • proporcionan una implementación predeterminada para los métodos elegidos (que está cubierto por su respuesta)
  • las clases abstractas pueden tener estado (variables de instancia), por lo que esta es una situación más en la que desea usarlas en lugar de interfaces

Completaría que las interfaces pueden tener variables pero por defecto son finales.
Tomasz Mularczyk

1

Esta es una buena pregunta. Los dos no son similares, pero pueden usarse por alguna de las mismas razones, como una reescritura. Al crearlo, es mejor utilizar Interface. Cuando se trata de clase, es bueno para depurar.


0

Abstract classes should be extended when you want to some common behavior to get extended. La superclase Abstract tendrá el comportamiento común y definirá el método abstracto / comportamiento específico que las subclases deben implementar.

Interfaces allows you to change the implementation anytime allowing the interface to be intact.


0

Este es mi entendimiento, espero que esto ayude

Clases abstractas:

  1. Puede tener variables miembro que se heredan (no se puede hacer en interfaces)
  2. Puede tener constructores (las interfaces no pueden)
  3. Sus métodos pueden tener cualquier visibilidad (es decir, privados, protegidos, etc., mientras que todos los métodos de interfaz son públicos)
  4. Puede tener métodos definidos (métodos con una implementación)

Interfaces:

  1. Puede tener variables, pero todas son variables finales estáticas públicas
    • valores constantes que nunca cambian con un alcance estático
    • las variables no estáticas requieren una instancia, y no puede crear una instancia de una interfaz
  2. Todos los métodos son abstractos (sin código en los métodos abstractos)
    • todo el código debe estar escrito en la clase que implementa la interfaz particular

0

Uso de resumen e interfaz:

Uno tiene "Es-una-relación" y otro tiene "Tiene-una-relación"

Las propiedades predeterminadas se han establecido en abstracto y las propiedades adicionales se pueden expresar a través de la interfaz.

Ejemplo: -> En los seres humanos tenemos algunas propiedades predeterminadas que son comer, dormir, etc. pero si alguien tiene otras actividades curriculares como nadar, jugar, etc., las podría expresar Interface.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.