c# - una - Clases abstractas vs interfaces
polimorfismo c# (14)
Estoy un poco confundido sobre el uso de clases abstractas en C #. En C ++, tiene sentido definir una plantilla que las clases que heredan de la clase abstracta pueden seguir. Pero, en C #, ¿la Interfaz no tiene el mismo propósito?
Es cierto que las clases abstractas pueden tener una implementación predeterminada que no es proporcionada por Interfaces. Entonces, si la implementación no necesita ser incluida en la clase base, ¿es mejor ir a Interfaces?
Es cierto que las clases abstractas pueden tener una implementación predeterminada que no es proporcionada por Interfaces. Entonces, si la implementación no necesita ser incluida en la clase base, ¿es mejor ir a Interfaces?
Si :). Si tiene sentido implementar algunos métodos en la clase base que serán comunes a todas las clases heredadas, debe usar una clase abstracta. Si la clase base solo se usaría para definir una interfaz pero no hay una lógica común entre las clases heredadas, use una interfaz.
En C # un gran factor disuasivo para el uso de clases abstractas es que solo puede usar una. Con las interfaces tiene la ventaja de no limitar la clase base para la implementación. Para este fin, siempre uso una interfaz, incluso si creo una clase base abstracta para ayudar con la implementación.
A menudo, otra molestia de las clases abstractas básicas es que tienden a depender de argumentos de plantilla. Esto puede hacer que sea muy difícil de utilizar para el resto de su código. La respuesta fácil para esto es proporcionar una interfaz para hablar con la clase abstracta sin conocer el argumento de tipo de la clase de plantilla.
Otros parecen estar escribiendo su respuesta más rápido, pero me permiten resumir ...
Utilice una interfaz. Si necesita compartir la implementación, también puede crear una clase base abstracta que proporcione detalles de implementación comunes.
Este artículo de CodeProject tiene mucha información sobre la diferencia entre los dos, incluida una tabla que compara y contrasta las características de cada uno.
Las interfaces definen el contrato entre clases, las formas en que las clases se llaman entre sí. Una clase puede implementar múltiples interfaces, pero solo puede heredar de una clase abstracta.
Esto se insinúa en algunas de las respuestas, pero no se establece explícitamente.
El hecho de que pueda implementar múltiples interfaces y solo heredar de una clase base, como si fueran dos caras de la misma moneda, no es una buena manera de verlo.
No piense en las interfaces como parte de una jerarquía de objetos. Por lo general, son solo pequeñas partes de la funcionalidad (o al menos específica si no pequeña) que su jerarquía de objetos real puede declarar como implementada. Tome IDisposable por ejemplo. Si fuera usted quien escribiera eso, ¿se preguntaría si debería haber sido una clase abstracta o una interfaz? Parece obvio que en este caso son dos cosas completamente diferentes. Quiero ser desechable. Piensa en IClonable e IEnumerable. Puede implementar aquellos en su clase sin tener que intentar y hacer que su clase se derive de algunas clases no relacionadas como List o Array. O tomar IEnumerator. Simplemente le da un tipo de vista MoveNext a un objeto. Mi clase puede proporcionar esa funcionalidad sin tener que derivar incómodamente de algún otro tipo de datos de recopilación secuencial que no tenga nada que ver con mi clase.
Interfaces y clases abstractas sirven para diferentes objetivos. Las interfaces se utilizan para declarar contratos para las clases, mientras que las clases abstractas se utilizan para compartir una implementación común.
Si solo utiliza clases abstractas, sus clases no pueden heredar de otras clases porque C # no admite la herencia múltiple. Si solo usas interfaces, tus clases no pueden compartir código común.
public interface IFoo
{
void Bar();
}
public abstract class FooBase : IFoo
{
public abstract void Bar()
{
// Do some stuff usually required for IFoo.
}
}
Ahora podemos usar la interfaz y la implementación base en varias situaciones.
public class FooOne : FooBase
{
public override void Bar()
{
base.Bar(); // Use base implementation.
// Do specialized stuff.
}
}
public class FooTwo : FooBase
{
public override void Bar()
{
// Do other specialized stuff.
base.Bar(); // Use base implementation.
// Do more specialized stuff.
}
}
// This class cannot use the base implementation from FooBase because
// of inheriting from OtherClass but it can still implement IFoo.
public class FooThree : OtherClass, IFoo
{
public virtual void Bar()
{
// Do stuff.
}
}
La regla que sigo al modelar es: Clases (resumen incluido) y estructuras de entidades modelo. Interfaces modelan el comportamiento. Se puede considerar que las entidades que implementan una interfaz exhiben comportamientos que la interfaz (contrato) expone.
Para tu primera pregunta, sí.
Para tu segunda respuesta te daré algunos consejos que he seguido.
- Use clases abstractas e interfaces en combinación para optimizar sus compromisos de diseño.
Usa una clase abstracta
Al crear una biblioteca de clases que se distribuirá o reutilizará ampliamente, especialmente para los clientes, use una clase abstracta con preferencia a una interfaz; Porque, simplifica el versionado.
Utilice una clase abstracta para definir una clase base común para una familia de tipos.
Utilice una clase abstracta para proporcionar un comportamiento predeterminado.
Subclase solo una clase base en una jerarquía a la que la clase pertenece lógicamente.
Usar una interfaz
Al crear un proyecto independiente que se puede cambiar a voluntad, use una interfaz con preferencia a una clase abstracta; Porque, ofrece más flexibilidad de diseño.
Use interfaces para introducir el comportamiento polimórfico sin subclasificación y para modelar la herencia múltiple, lo que permite que un tipo específico admita numerosos comportamientos.
Utilice una interfaz para diseñar una jerarquía polimórfica para los tipos de valor.
Utilice una interfaz cuando realmente se pretende un contrato inmutable.
Una interfaz bien diseñada define un rango de funcionalidad muy específico. Dividir las interfaces que contienen funcionalidad no relacionada.
Puede implementar cualquier número de interfaces, pero solo puede heredar una clase. Así que las Clases y las Interfaces son bestias bastante diferentes en C # y no puedes usarlas indistintamente. En C # las clases abstractas son todavía clases, no interfaces.
Si bien es cierto que una clase abstracta sin implementación es equivalente a una interfaz, las interfaces y las clases abstractas se usan para diferentes cosas.
Las interfaces se pueden utilizar para el polimorfismo en el sentido más general. Por ejemplo, ICollection
se utiliza para definir la interfaz para todas las colecciones (hay bastantes). Aquí está definiendo las operaciones que desea realizar en un determinado tipo de tipo. Hay muchos otros usos (como comprobabilidad, inyección de dependencia, etc.). Además, las interfaces se pueden mezclar y esto funciona tanto conceptual como técnicamente.
Las clases abstractas tienen más que ver con el comportamiento templatable, donde los métodos virtuales son un lugar para "llenar los vacíos". Obviamente no puedes mezclar clases abstractas (al menos, no en C #).
Si no tiene ningún código predeterminado / común, vaya con una interfaz.
Una clase abstracta también puede servir como plantilla, donde define los pasos de algunos algoritmos y el orden en que se llaman, y las clases derivadas proporcionan la implementación de estos pasos:
public abstract class Processor
{
// this is the only public method
// implements the order of the separate steps
public void Process()
{
Step1();
Step2();
//...
}
// implementation is provided by derived classes
protected abstract void Step1();
protected abstract void Step2();
}
Siempre prefiero las interfaces siempre que la clase base no tenga alguna implementación realmente "resistente" que ahorre mucho tiempo a los implementadores. dar que .net permite solo una herencia de clase base, obligar a los usuarios a heredar es una gran limitación.
Siempre se debe preferir la programación a interfaces que a clases concretas.
Si también desea tener una implementación predeterminada, aún puede crear una clase base que implemente su (s) interfaz (es).
Tenga en cuenta que con C # 3, puede proporcionar un comportamiento predeterminado para las interfaces mediante el uso de métodos de extensión. Hay algunas limitaciones, sin embargo, y las clases abstractas todavía tienen su lugar.
Todavía me gusta proporcionar una implementación abstracta predeterminada de una interfaz, asumiendo que es una interfaz sustancial (y tiene sentido). Nunca se sabe cuándo se puede agregar algo a la interfaz que tiene una implementación predeterminada fácil que podría incluirse y darse "gratis" a cualquiera que herede de la clase base abstracta.