Al utilizar una interfaz en lugar de una clase abstracta y viceversa?


Esta puede ser una pregunta genérica OOP. Quería hacer una comparación genérica entre una interfaz y una clase abstracta sobre la base de su uso.

Cuándo se quiere usar una interfaz y cuándo se quiere usar una clase abstracta?

Author: Ravindra babu, 2009-01-26

21 answers

Escribí un artículo sobre eso:

Clases abstractas e interfaces

Resumiendo:

Cuando hablamos de clases abstractas estamos definiendo características de un tipo de objeto; especificando qué es un objeto.

Cuando hablamos de una interfaz y definimos capacidades que prometemos proporcionar, estamos hablando de establecer un contrato sobre lo que el objeto puede hacer.

 360
Author: Jorge Córdoba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-21 19:34:30

Una clase abstracta puede tener estado o funcionalidad compartidos. Una interfaz es solo una promesa de proporcionar el estado o la funcionalidad. Una buena clase abstracta reducirá la cantidad de código que debe reescribirse porque su funcionalidad o estado puede compartirse. La interfaz no tiene información definida para compartir

 386
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:52:47

Personalmente, casi nunca tengo la necesidad de escribir clases abstractas.

La mayoría de las veces veo que las clases abstractas se usan (mal), es porque el autor de la clase abstracta está usando el patrón "Método de plantilla".

El problema con el "método de plantilla" es que casi siempre es un poco reentrante - la clase "derivada" sabe no solo del método "abstracto" de su clase base que está implementando, sino también de los métodos públicos de la clase base, aunque la mayoría veces no es necesario llamarlos.

(Excesivamente simplificado) ejemplo:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

Así que aquí, el autor de esta clase ha escrito un algoritmo genérico y pretende que la gente lo use "especializándolo" proporcionando sus propios "hooks" - en este caso, un método de "comparación".

Así que el uso previsto es algo como esto:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

El problema con esto es que has acoplado indebidamente dos conceptos:

  1. Una forma de comparar dos elementos (qué elemento debe ir primero)
  2. Un método para ordenar elementos (es decir, quicksort vs merge sort, etc.)

En el código anterior, teóricamente, el autor del método "compare" puede re-entrantly volver a llamar al método "Sort" de la superclase... aunque en la práctica nunca querrán o necesitarán hacer esto.

El precio que paga por este acoplamiento innecesario es que es difícil cambiar la superclase, y en la mayoría de los idiomas OO, imposible cambiarlo en tiempo de ejecución.

El el método alternativo es usar el patrón de diseño" Estrategia " en su lugar:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

Así que note ahora: Todo lo que tenemos son interfaces, e implementaciones concretas de esas interfaces. En la práctica, realmente no necesitas nada más para hacer un diseño OO de alto nivel.

Para "ocultar" el hecho de que hemos implementado "ordenación de nombres" mediante el uso de una clase "QuickSort" y un "NameComparator", todavía podríamos escribir un método de fábrica en alguna parte:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Cualquier tiempo que tenga una clase abstracta puedes hacerlo... incluso cuando hay una relación natural de reingreso entre la clase base y la clase derivada, generalmente vale la pena hacerlas explícitas.

Un pensamiento final: Todo lo que hemos hecho anteriormente es "componer" una función "NameSorting" usando una función "QuickSort" y una función "NameComparison"... en un lenguaje de programación funcional, este estilo de programación se vuelve aún más natural, con menos código.

 75
Author: Paul Hollingsworth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-17 23:42:56

OK, después de haber "grokked" esto yo mismo - aquí está en términos legos (siéntase libre de corregirme si estoy equivocado) - Sé que este tema es oooooold, pero alguien más podría tropezar con él un día...

Las clases abstractas le permiten crear un blueprint, y le permiten construir (implementar) propiedades y métodos que desea que posean TODOS sus descendientes.

Una interfaz por otro lado solo le permite declarar que desea propiedades y / o métodos con un nombre dado para existir en todas las clases que lo implementan - pero no especifica cómo debe implementarlo. Además, una clase puede implementar MUCHAS interfaces, pero solo puede extender UNA clase abstracta. Una interfaz es más una herramienta arquitectónica de alto nivel (que se vuelve más clara si comienzas a comprender los patrones de diseño): un abstracto tiene un pie en ambos campos y también puede realizar parte del trabajo sucio.

¿Por qué usar uno sobre el otro? El primero permite una definición más concreta de descendientes - este último permite mayor polimorfismo . Este último punto es importante para el usuario final/codificador, que puede utilizar esta información para implementar el A. P.I(nterface) en una variedad de combinaciones/formas para satisfacer sus necesidades.

Creo que este fue el momento de la" bombilla " para mí-pensar en interfaces menos desde la perspectiva del autor y más desde la de cualquier codificador que viene más tarde en la cadena que está agregando implementación a un proyecto, o extendiendo una API.

 38
Author: sunwukung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-07 12:10:57

Mis dos centavos:

Una interfaz básicamente define un contrato, al que cualquier clase implementadora debe adherirse(implementar los miembros de la interfaz). No contiene ningún código.

Por otro lado, una clase abstracta puede contener código, y puede haber algunos métodos marcados como abstractos que una clase heredera debe implementar.

Las situaciones raras que he usado clases abstractas es cuando tengo alguna funcionalidad predeterminada que la clase heredera podría no ser interesante en sobreescritura, digamos una clase base abstracta, de la que heredan algunas clases especializadas.

Ejemplo (¡muy rudimentario!): Considere una clase base llamada Cliente que tiene métodos abstractos como CalculatePayment(), CalculateRewardPoints() y algunos métodos no abstractos como GetName(), SavePaymentDetails().

Las clases especializadas como RegularCustomer y GoldCustomer heredarán de la clase base Customer e implementarán su propia lógica de métodos CalculatePayment() y CalculateRewardPoints(), pero reutilizarán los métodos GetName() y SavePaymentDetails().

Puedes añadir más funcionalidad a una clase abstracta (métodos no abstractos es decir) sin afectar a las clases secundarias que estaban utilizando una versión anterior. Mientras que agregar métodos a una interfaz afectaría a todas las clases que lo implementan, ya que ahora tendrían que implementar los miembros de la interfaz recién agregados.

Una clase abstracta con todos los miembros abstractos sería similar a una interfaz.

 33
Author: PreethaA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-24 17:14:57

Cuándo hacer lo que es una cosa muy simple si tienes el concepto claro en tu mente.

Las clases abstractas se pueden Derivar mientras que las Interfaces se pueden Implementar. Hay alguna diferencia entre los dos. Cuando se deriva una clase Abstracta, la relación entre la clase derivada y la clase base 'es una' relación. por ejemplo, un Perro es un Animal, una Oveja es un Animal, lo que significa que una clase derivada hereda algunas propiedades de la clase base.

Considerando que para implementación de interfaces, la relación es "puede ser". por ejemplo, un Perro puede ser un perro espía. Un perro puede ser un perro de circo. Un perro puede ser un perro de raza. Lo que significa que implementas ciertos métodos para adquirir algo.

Espero ser claro.

 28
Author: Aamir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 10:41:12

Si estás viendo java como lenguaje OOP,

"la interfaz no proporciona la implementación del método" ya no es válido con Java 8 launch. Ahora java proporciona implementación en la interfaz para los métodos predeterminados.

En términos simples, me gustaría usar

interfaz: Para implementar un contrato por múltiples objetos no relacionados. Proporciona " TIENE Una capacidad".

clase abstracta: Para implementar el mismo o diferente comportamiento entre múltiples objetos relacionados. Establece que " ES Una relación".

Oracle sitio web proporciona diferencias clave entre interface y abstract clase.

Considere usar clases abstractas si:

  1. desea compartir código entre varias clases estrechamente relacionadas.
  2. Usted espera que las clases que amplían su clase abstracta tengan muchos métodos o campos comunes, o requieran modificadores de acceso otros que público (como protegido y privado).
  3. Desea declarar campos no estáticos o no finales.

Considere usar interfaces si:

  1. Esperas que las clases no relacionadas implementen tu interfaz. Por ejemplo,muchos objetos no relacionados pueden implementar la interfaz Serializable.
  2. Desea especificar el comportamiento de un tipo de datos en particular, pero sin preocuparse por quién implementa su comportamiento.
  3. Usted quiere tomar ventaja de herencia múltiple de tipo.

Ejemplo:

Clase abstracta (ES Una relación)

Reader es una clase abstracta.

BufferedReader es un Reader

FileReader es un Reader

FileReader y BufferedReader se usan para un propósito común : Leer datos, y se relacionan a través de la clase Reader.

Interfaz (TIENE Una capacidad)

Serializable es una interfaz.

Suponga que tiene dos clases en su aplicación, que están implementando Serializable interfaz

Employee implements Serializable

Game implements Serializable

Aquí no se puede establecer ninguna relación a través de Serializable interfaz entre Employee y Game, que están destinados a un propósito diferente. Ambos son capaces de Serializar el estado y la comparación termina allí.

Echa un vistazo a estos mensajes :

¿Cómo debería haber explicado la diferencia entre una Interfaz y un Clase abstracta?

 25
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-27 14:01:51

Escribí un artículo sobre cuándo usar una clase abstracta y cuándo usar una interfaz. Hay mucha más diferencia entre ellos que "uno ES-A... y uno PUEDE HACERLO...". Para mí, esas son respuestas enlatadas. Menciono algunas razones para usar cualquiera de ellas. Espero que ayude.

Http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-12 19:19:33

1.Si está creando algo que proporciona una funcionalidad común a clases no relacionadas, utilice una interfaz.

2.Si está creando algo para objetos que están estrechamente relacionados en una jerarquía, use una clase abstracta.

 9
Author: kuttychutty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-04 04:05:43

Las clases pueden heredar solo de una clase base, por lo que si desea usar clases abstractas para proporcionar polimorfismo a un grupo de clases, todas deben heredar de esa clase. Las clases abstractas también pueden proporcionar miembros que ya se han implementado. Por lo tanto, puede garantizar una cierta cantidad de funcionalidad idéntica con una clase abstracta, pero no con una interfaz.

Aquí hay algunas recomendaciones para ayudarlo a decidir si usar una interfaz o una clase abstracta para proporcione polimorfismo para sus componentes.

  • Si prevé crear varias versiones de su componente, cree una clase abstracta. Las clases abstractas proporcionan una manera simple y fácil de versionar sus componentes. Al actualizar la clase base, todas las clases herederas se actualizan automáticamente con el cambio. Las interfaces, por otro lado, no se pueden cambiar una vez creadas de esa manera. Si se requiere una nueva versión de una interfaz, debe crear una interfaz completamente nueva.
  • Si la funcionalidad que está creando será útil en una amplia gama de objetos dispares, utilice una interfaz. Las clases abstractas deben usarse principalmente para objetos que están estrechamente relacionados, mientras que las interfaces son las más adecuadas para proporcionar funcionalidad común a clases no relacionadas.
  • Si está diseñando pequeños y concisos bits de funcionalidad, utilice interfaces. Si está diseñando unidades funcionales grandes, utilice una clase abstracta.
  • Si desea proporcionar funcionalidad común implementada entre todas las implementaciones de su componente, use una clase abstracta. Las clases abstractas le permiten implementar parcialmente su clase, mientras que las interfaces no contienen ninguna implementación para ningún miembro.

Copiado de:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx

 3
Author: Mazhar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-13 08:36:08

Considere usar clases abstractas si cualquiera de estas afirmaciones se aplica a su situación:

  1. desea compartir código entre varias clases estrechamente relacionadas.
  2. Usted espera que las clases que amplían su clase abstracta tengan muchos métodos o campos comunes o requieran modificadores de acceso que no sean públicos (como protegidos y privados).
  3. Desea declarar campos no estáticos o no finales. Esto le permite definir métodos que pueden acceder y modificar el estado de el objeto al que pertenecen.

Considere usar interfaces si cualquiera de estas instrucciones se aplica a su situación:

  1. Esperas que las clases no relacionadas implementen tu interfaz. Por ejemplo, las interfaces Comparables y Clonables son implementadas por muchas clases no relacionadas.
  2. Desea especificar el comportamiento de un tipo de datos en particular, pero sin preocuparse por quién implementa su comportamiento.
  3. Usted quiere tomar ventaja de múltiples herencia.

Fuente

 3
Author: Abhijeet Ashok Muneshwar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-21 07:11:02

Creo que la forma más sucinta de decirlo es la siguiente:

Propiedades Compartidas => clase abstracta.
Funcionalidad compartida = > interfaz.

Y para decirlo menos sucintamente...

Ejemplo de Clase abstracta:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Dado que los animales tienen una propiedad compartida - número de patas en este caso - tiene sentido hacer una clase abstracta que contenga esta propiedad compartida. Esto también nos permite escribir código común que opera en esa propiedad. Para ejemplo:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Ejemplo de interfaz:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Tenga en cuenta aquí que las Vuvuzelas y los coches son cosas completamente diferentes, pero tienen una funcionalidad compartida: hacer un sonido. Por lo tanto, una interfaz tiene sentido aquí. Además, permitirá a los programadores agrupar cosas que producen sonidos bajo una interfaz común {IMakeSound en este caso. Con este diseño, podría escribir el siguiente código:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

¿Puedes saber lo que eso produciría?

Por último, usted puede combina los dos.

Ejemplo combinado:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

Aquí, estamos requiriendo que todos BaseAnimal hagan un sonido, pero aún no sabemos su implementación. En tal caso, podemos abstraer la implementación de la interfaz y delegar su implementación a sus subclases.

Un último punto, recuerde cómo en el ejemplo de clase abstracta pudimos operar sobre las propiedades compartidas de diferentes objetos y en el ejemplo de interfaz pudimos invocar la funcionalidad compartida de diferentes objetos? En este último ejemplo, podríamos hacer ambas cosas.

 3
Author: Domn Werner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-14 15:23:44

Las respuestas varían entre idiomas. Por ejemplo, en Java una clase puede implementar (heredar de) múltiples interfaces, pero solo heredar de una clase abstracta. Así que las interfaces le dan más flexibilidad. Pero esto no es cierto en C++.

 2
Author: Nick Fortescue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:55:12

Para mí, iría con interfaces en muchos casos. Pero prefiero las clases abstractas en algunos casos.

Las clases en OO generalmente se refieren a la implementación. Utilizo clases abstractas cuando quiero forzar algunos detalles de implementación a los niños más voy con interfaces.

Por supuesto, las clases abstractas son útiles no solo para forzar la implementación, sino también para compartir algunos detalles específicos entre muchas clases relacionadas.

 2
Author: La VloZ Merrill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-13 20:34:21

Utilice una clase abstracta si desea proporcionar algunas implementaciones básicas.

 1
Author: Sebastian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:48:46

En java puede heredar de una clase (abstracta) para" proporcionar "funcionalidad y puede implementar muchas interfaces para" garantizar " funcionalidad

 1
Author: Peter Miehle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:52:18

Puramente sobre la base de la herencia, se usaría un Abstracto donde se está definiendo claramente descendiente, relaciones abstractas (es decir, animal->gato) y/o requieren la herencia de propiedades virtuales o no públicas, especialmente estado compartido (que las interfaces no pueden soportar).

Debe tratar de favorecer la composición (a través de la inyección de dependencias) sobre la herencia, aunque puede, y tenga en cuenta que las interfaces que son contratos soportan pruebas unitarias, separación de preocupaciones y herencia múltiple de una manera que los Abstractos no pueden.

 1
Author: annakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:56:55

Un lugar interesante donde las interfaces funcionan mejor que las clases abstractas es cuando necesita agregar funcionalidad adicional a un grupo de objetos (relacionados o no). Si no puede darles una clase abstracta base (por ejemplo, son sealed o ya tienen un padre), puede darles una interfaz ficticia (vacía) en su lugar, y luego simplemente escribir métodos de extensión para esa interfaz.

 1
Author: Dmitri Nesteruk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 11:00:47

Esta puede ser una llamada muy difícil de hacer...

Un puntero que puedo dar: Un objeto puede implementar muchas interfaces, mientras que un objeto solo puede heredar una clase base( en un lenguaje OO moderno como c#, sé que C++ tiene herencia múltiple, pero ¿no está mal visto?)

 0
Author: Mesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:53:30

Una clase abstracta puede tener implementaciones.

Una interfaz no tiene implementaciones, simplemente define un tipo de contrato.

También puede haber algunas diferencias dependientes del lenguaje: por ejemplo, C# no tiene herencia múltiple, pero se pueden implementar varias interfaces en una clase.

 0
Author: Gerrie Schenck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-26 08:54:14

La regla básica es: Para los "sustantivos" usan Clase Abstracta y para los"Verbos" usan interfaz

Ej: car es una clase abstracta y drive, podemos convertirla en una interfaz.

 -1
Author: GANI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-09 08:34:10