"Clase abstracta" e "interfaz" son conceptos similares, siendo la interfaz la más abstracta de las dos. Un factor diferenciador es que las clases abstractas proporcionan implementaciones de métodos para clases derivadas cuando es necesario. Sin embargo, en C #, este factor diferenciador se ha reducido por la reciente introducción de métodos de extensión, que permiten que se proporcionen implementaciones para los métodos de interfaz. Otro factor diferenciador es que una clase puede heredar solo una clase abstracta (es decir, no hay herencia múltiple), pero puede implementar múltiples interfaces. Esto hace que las interfaces sean menos restrictivas y más flexibles. Entonces, en C #, ¿cuándo debemos usar clases abstractas en lugar de interfaces con métodos de extensión?
Un ejemplo notable del modelo de interfaz + método de extensión es LINQ, donde se proporciona la funcionalidad de consulta para cualquier tipo que se implemente a IEnumerable
través de una multitud de métodos de extensión.
fuente
Respuestas:
Cuando necesita que se implemente una parte de la clase. El mejor ejemplo que he usado es el patrón de método de plantilla .
Por lo tanto, puede definir los pasos que se tomarán cuando se llame a Do (), sin conocer los detalles de cómo se implementarán. Las clases derivadas deben implementar los métodos abstractos, pero no el método Do ().
Los métodos de extensiones no satisfacen necesariamente la parte de la ecuación "debe ser parte de la clase". Además, iirc, los métodos de extensión no pueden (parece ser) tener un alcance público.
editar
La pregunta es más interesante de lo que originalmente había dado crédito. Tras un examen más detallado, Jon Skeet respondió una pregunta como esta en SO a favor del uso de interfaces + métodos de extensión. Además, una desventaja potencial es usar la reflexión contra una jerarquía de objetos diseñada de esta manera.
Personalmente, tengo problemas para ver el beneficio de alterar una práctica común en la actualidad, pero también veo pocos o ningún inconveniente al hacerlo.
Cabe señalar que es posible programar de esta manera en muchos idiomas a través de clases de utilidad. Las extensiones solo proporcionan el azúcar sintáctico para que los métodos parezcan pertenecer a la clase.
fuente
Do()
se definirán como un método de extensión. Y los métodos que quedan para la definición de clases derivadas comoDoThis()
serán miembros de la interfaz principal. Y con las interfaces, puede soportar múltiples implementaciones / herencia. Y vea esto- odetocode.com/blogs/scott/archive/2009/10/05/…Se trata de lo que quieres modelar:
Las clases abstractas funcionan por herencia . Al ser clases base simplemente especiales, modelan algunos is-a -Relación.
Por ejemplo, un perro es un animal, entonces tenemos
Como no tiene sentido crear realmente un animal genérico (¿cómo se vería?), Hacemos esta
Animal
clase baseabstract
, pero sigue siendo una clase base. Y laDog
clase no tiene sentido sin ser unAnimal
.Las interfaces, por otro lado, son una historia diferente. No usan herencia, pero proporcionan polimorfismo (que también se puede implementar con herencia). No modelan una relación es-es , pero más bien sí es compatible .
Tomemos, por ejemplo
IComparable
, un objeto que admite ser comparado con otro .La funcionalidad de una clase no depende de las interfaces que implementa, la interfaz solo proporciona una forma genérica de acceder a la funcionalidad. Todavía podríamos
Dispose
de aGraphics
o aFileStream
sin que se implementenIDisposable
. La interfaz solo relaciona los métodos juntos.En principio, uno podría agregar y eliminar interfaces como extensiones sin cambiar el comportamiento de una clase, simplemente enriqueciendo el acceso a ella. ¡Sin embargo, no puedes quitar una clase base ya que el objeto dejaría de tener sentido!
fuente
Animal
resumen. Esto le permite escribirabstract
funciones para que sean especializadas por las clases derivadas. O más en términos de programación: probablemente no tenga sentido crear aUserControl
, pero como aButton
es aUserControl
, entonces tenemos el mismo tipo de relación clase / clase base.Me acabo de dar cuenta de que no he usado clases abstractas (al menos no creadas) en años.
La clase abstracta es una bestia algo extraña entre la interfaz y la implementación. Hay algo en las clases abstractas que hormiguea mi sentido de araña. Yo diría que uno no debe "exponer" la implementación detrás de la interfaz de ninguna manera (o hacer ningún vínculo).
Incluso si existe la necesidad de un comportamiento común entre las clases que implementan una interfaz, usaría una clase auxiliar independiente, en lugar de una clase abstracta.
Yo iría por las interfaces.
fuente
En mi humilde opinión, creo que hay una mezcla de conceptos aquí.
Las clases usan un cierto tipo de herencia, mientras que las interfaces usan un tipo diferente de herencia.
Ambos tipos de herencia son importantes y útiles, y cada uno tiene sus pros y sus contras.
Empecemos desde el principio.
La historia con interfaces comienza mucho tiempo atrás con C ++. A mediados de la década de 1980, cuando se desarrolló C ++, la idea de las interfaces como un tipo diferente de tipo aún no se realizó (llegaría a tiempo).
C ++ solo tenía un tipo de herencia, el tipo de herencia utilizada por las clases, llamada herencia de implementación.
Para poder aplicar la recomendación de GoF Book: "Para programar para la interfaz y no para la implementación", C ++ admite clases abstractas y herencia de implementación múltiple para poder hacer lo que las interfaces en C # son capaces (¡y útiles!) De hacer .
C # presenta un nuevo tipo de tipo, interfaces y un nuevo tipo de herencia, herencia de interfaz, para ofrecer al menos dos formas diferentes de soportar "Programar para la interfaz y no para la implementación", con una advertencia importante: C # solamente admite herencia múltiple con herencia de interfaz (y no con herencia de implementación).
Entonces, las razones arquitectónicas detrás de las interfaces en C # es la recomendación de GoF.
Espero que esto pueda ser de ayuda.
Saludos cordiales, Gastón
fuente
La aplicación de métodos de extensión a una interfaz es útil para aplicar un comportamiento común en las clases que pueden compartir solo una interfaz común. Dichas clases pueden existir y estar cerradas a extensiones por otros medios.
Para nuevos diseños, preferiría el uso de métodos de extensión en las interfaces. Para una jerarquía de tipos, los métodos de extensión proporcionan un medio para extender el comportamiento sin tener que abrir toda la jerarquía para su modificación.
Sin embargo, los métodos de extensión no pueden acceder a la implementación privada, por lo tanto, en la parte superior de una jerarquía, si necesito encapsular la implementación privada detrás de una interfaz pública, entonces una clase abstracta sería la única forma.
fuente
Creo que en C # no se admite la herencia múltiple y por eso se introduce el concepto de interfaz en C #.
En el caso de las clases abstractas, tampoco se admite la herencia múltiple. Por lo tanto, es fácil decidir si utilizar clases o interfaces abstractas.
fuente
Estoy en el proceso de implementar una clase abstracta en mi proyecto simplemente porque C # no admite operadores (conversiones implícitas, en mi caso) en las interfaces.
fuente