Clase abstracta vs Interfaz en Java

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

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

R: Si estamos usando un patrón de diseño de método de plantilla.

Estoy en lo correcto ?

Lo siento si no pude express la pregunta con claridad.
Sé la diferencia básica entre la clase abstracta y la interfaz.

1) use la clase abstracta cuando el requisito es tal que necesitamos implementar la misma funcionalidad en cada subclase para una operación específica (implementar el método) y diferentes funcionalidades 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: ¿Existen otros escenarios, además de los mencionados anteriormente, en los que específicamente se requiere el uso de la clase abstracta (se ve que el patrón de diseño del método de la plantilla se basa conceptualmente solo en esto)?

Interfaz vs. Clase abstracta

Elegir entre estos dos realmente depende de lo que quieras hacer, pero afortunadamente 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 no siempre sería bueno.

Abstract classes deberían usarse principalmente para objetos que están estrechamente relacionados. Interfaces son mejores para proporcionar una funcionalidad común para clases no relacionadas.

Cuándo usar interfaces

Una interfaz permite a alguien comenzar de cero para implementar su interfaz o implementar su interfaz en algún otro código cuyo propósito original o primario fuera bastante diferente de su interfaz. Para ellos, su interfaz es solo incidental, algo que debe agregarse a su código para poder usar su paquete. La desventaja es que todos los métodos en la interfaz deben ser públicos. Puede que no quieras 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 truco es que el código que lo usa debe usar tu clase como base. Eso puede ser muy inconveniente si los otros progtwigdores 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 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 abstracta.

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

Sí, si usa JAXB. No le gustan las interfaces. Debes usar clases abstractas o solucionar esta limitación con generics.

De una publicación de blog personal:

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 efectos dominantes en la implementación de clases (mantenimiento del diseño)
  6. JAXB no puede tratar 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 deberían usarse para definir contratos (lo que se 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 constantes estáticas y 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 dominantes en la extensión de clases (mantenimiento de implementación)
  6. Agregar un nuevo método a una clase abstracta no tiene efecto dominó en extender clases
  7. Una clase abstracta puede implementar una interfaz
  8. Las clases abstractas pueden implementar métodos privados y protegidos

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

La interfaz se usa cuando tiene el escenario de que todas las clases tienen la misma estructura, pero tienen una funcionalidad totalmente diferente.

La clase abstracta se usa cuando se tiene el escenario de que todas las clases tienen la misma estructura pero algunas mismas y algunas funcionalidades diferentes.

Eche un vistazo al artículo: http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html

Usted no es correcto Hay muchos escenarios Simplemente no es posible reducirlo a una sola regla de 8 palabras.

¿Cuál debería usar, clases abstractas o interfaces?

Considere usar clases abstractas si cualquiera de estas afirmaciones se aplica a su escenario:

Desea compartir el 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 que requieran modificadores de acceso que no sean públicos (como protegidos y privados).

Desea 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 usar interfaces si cualquiera de estas afirmaciones se aplica a su situación:

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

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

Desea aprovechar la herencia múltiple de tipo.

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

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 se puede implementar en la superclase y, por lo tanto, se hereda en las subclases

También cité lo siguiente del libro “software architecture design ppatterns in java”

“En el lenguaje de progtwigción Java no hay soporte para 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 adolecen de 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 ellos Los métodos representan la parte invariable de la funcionalidad y tienen exactamente la misma implementación en todas las clases de implementadores. Esto conduce a un código redundante. El siguiente ejemplo demuestra cómo se puede usar el patrón abstracto de clase principal en tales casos sin requerir implementaciones de métodos redundantes “.

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 puede contener solo constantes, firmas de métodos, métodos predeterminados, métodos estáticos y tipos nesteds. Los cuerpos de método existen solo para métodos predeterminados y métodos estáticos.

Como mencionaste en tu pregunta, la clase abstracta es más adecuada para el patrón de método de plantilla donde tienes que crear esqueleto. La interfaz no se puede usar 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 estado con subclases.

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


En cuanto a la segunda parte de su pregunta, que es válida para la mayoría de los lenguajes de progtwigción, incluido Java antes de la versión 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 que la clase abstracta interactúe antes con las dos consideraciones anteriores, debe volver a pensar ahora ya que los métodos predeterminados han agregado poderosas capacidades a las interfaces.

Los métodos predeterminados le permiten agregar nuevas funcionalidades 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 la interfaz y la clase abstracta, la cita de la documentación de Oracle que:

Las clases abstractas son similares a las interfaces. No puede crear instancias de ellos, y pueden contener una combinación de métodos declarados con o sin implementación. Sin embargo, con 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 usted declara o define (como métodos predeterminados) son públicos. Además, puede extender solo una clase, sea o no abstracta, mientras que puede implementar cualquier cantidad 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 está inclinando más hacia las interfaces ahora .

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

Algunos patrones de diseño usan clases abstractas (a través de interfaces) aparte del patrón de método de Plantilla.

Patrones de creación:

Abstract_factory_pattern

Patrones estructurales:

Decorator_pattern

Patrones de comportamiento:

Mediator_pattern

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

  • proporcionan 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 las interfaces

La respuesta más breve 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 el número de clase abstracto de métodos que necesita implementar, puede haber menos.

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 hacer subclase y definir esos métodos, realmente defines el comportamiento principal. El comportamiento subyacente no puede estar en una interfaz ya que la interfaz no define nada, solo lo 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.

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

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

 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 la mesa de ventas y en otras líneas comerciales pueden comenzar a interactuar con su sistema para agregar funcionalidad de ubicación de pedidos a sus aplicaciones existentes. ¡Y aún no has comenzado a construir! Este es el poder de las interfaces.

Así que sigue adelante y construye el sistema para los operadores bursátiles ; ¡han escuchado que su sistema tiene una función para encontrar acciones baratas y están ansiosas por probarlo! findGoodDeals() este comportamiento en un método llamado findGoodDeals() , pero también te das cuenta de que hay muchas cosas desordenadas involucradas en la conexión a los mercados. Por ejemplo, debe 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);  } public void findGoodDeals(); deals =  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 les importa a los traders.

Ahora aquí es donde las clases abstractas entran en juego. Su jefe le informa que los operadores de divisas también quieren usar su sistema. Y mirando a los mercados de divisas, verá que la fontanería es casi idéntica a los mercados bursátiles. De hecho, connectToMarket() se puede reutilizar textualmente para conectarse a los mercados de divisas. Sin embargo, findGoodDeals() es un concepto muy diferente en el ámbito monetario. Entonces, antes de pasar la base de código al niño de intercambio extranjero a través del océano, primero se refactoriza en una clase abstract , dejando findGoodDeals() aplicar

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

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

 public class StockTradeSystem extends ABCTradeSystem{ public void findGoodDeals(); deals =  System.out.println("The best stocks to buy are: " + deals); } 

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

 public class CurrencyTradeSystem extends ABCTradeSystem{ public void findGoodDeals(); ccys =  System.out.println("The best FX spot rates are: " + ccys); } 

La progtwigción en una interfaz es poderosa, pero las aplicaciones similares a menudo vuelven a implementar los métodos de forma casi idéntica. El uso de una clase abstracta evita las reimplantaciones, al tiempo que preserva la potencia de la interfaz.

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

Esta es una buena pregunta. Las dos no son similares, pero se pueden usar por alguna de las mismas razones, como una reescritura. Al crearlo, lo mejor es usar la interfaz. Cuando se trata de clase, es bueno para la depuración.

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

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

Este es mi entendimiento, espero que esto ayude

Clases abstractas:

  1. Puede tener variables de miembros 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: privado, protegido, 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 scope estático
    • las variables no estáticas requieren una instancia y no se puede crear una instancia de una interfaz
  2. Todos los métodos son abstractos (sin código en métodos abstractos)
    • todo el código tiene que escribirse realmente en la clase que implementa la interfaz particular

Uso de resumen e interfaz:

Uno tiene “Is-A-Relationship” y otro tiene “Has-A-Relationship”

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

Ejemplo: -> En los seres humanos tenemos algunas propiedades predeterminadas que son comer, dormir, etc., pero si alguien tiene alguna otra actividad curricular como nadar, jugar, etc., eso podría ser expresado por Interface.