¿Interfaz o clase abstracta?

Para mi nuevo Pet-Project tengo una pregunta para diseño, eso ya está decidido, pero también quiero otras opiniones sobre eso.

Tengo dos clases (simplificadas):

class MyObject { string name {get;set;} enum relation {get;set;} int value {get;set;} } class MyObjectGroup { string name {get;set;} enum relation {get;set;} int value {get;set;} List myobjects {get;set;} } 

Más adelante en el proyecto, MyObjectGroup y MyObject deberían usarse por igual. Para esto podría ir de dos maneras:

  • Crear una interfaz: IObject
  • Crear una clase abstracta: ObjectBase

Decidí seguir el camino de la interfaz, que más adelante en el código no debo escribir ObjectBase todo el tiempo, sino IObject solo por facilidad, pero ¿qué otros aspectos positivos de esta manera?

Y segundo, ¿qué hay de agregar IXmlSerializable a toda la historia? Deje que la interfaz herede de IXmlSerializable o tiene más aspectos positivos para implementar IXmlSerializable en la clase base abstracta?

En términos generales, el enfoque que uso en este tipo de situación es tener una interfaz y una clase abstracta. Las interfaces definen, bueno, la interfaz. La clase abstracta es simplemente una ayuda.

Realmente no puedes equivocarte con este enfoque. Las interfaces le dan la flexibilidad para cambiar la implementación. Las clases abstractas le dan un código repetitivo y un código auxiliar que no está obligado a usar, que de otra manera sería si sus métodos se definieran explícitamente en términos de una clase abstracta.

Estas son algunas de las diferencias entre las interfaces y las clases abstractas.

1A. Una clase puede heredar (Implementar) una o más interfaces. Entonces, en C #, las interfaces se usan para lograr herencia múltiple.
1B. Una clase puede heredar solo una clase abstracta.

2A. Una interfaz no puede proporcionar ningún código, solo la firma.
2B. Una clase abstracta puede proporcionar un código completo y predeterminado y / o solo los detalles que deben anularse.

3A. Una interfaz no puede tener modificadores de acceso para los subs, funciones, propiedades, etc., todo se asume como público.
3B. Una clase abstracta puede contener modificadores de acceso para los subs, funciones, propiedades.

4A. Las interfaces se utilizan para definir las capacidades periféricas de una clase. Por ej. Un Ship y un Car pueden implementar una interfaz IMovable .
4B. Una clase abstracta define la identidad central de una clase y allí se usa para objetos.

5A. Si varias implementaciones solo comparten firmas de métodos, entonces es mejor usar interfaces.
5B. Si varias implementaciones son del mismo tipo y usan un comportamiento o estado común, entonces es mejor usar la clase abstracta.

6A. Si agregamos un nuevo método a una interfaz, entonces debemos rastrear todas las implementaciones de la interfaz y definir la implementación para el nuevo método.
6B. Si agregamos un nuevo método a una clase abstracta, entonces tenemos la opción de proporcionar una implementación predeterminada y, por lo tanto, todo el código existente podría funcionar correctamente.

7A. Una interfaz no puede tener campos definidos.
7B. Una clase abstracta puede tener campos y constantes definidas.

8A. Una interfaz no puede tener constructor.
8B. Una clase abstracta puede tener constructores predeterminados implementados.

9A. Una interfaz solo puede heredar de otras interfaces.
9B. Una clase abstracta puede heredar de interfaces, clase abstracta o incluso clase.

La interfaz sería mi predeterminada hasta que haya una razón para usar una clase base, ya que toma menos decisiones para nosotros.

No involucraría IXmlSerializable menos que tuviera que hacerlo; es una interfaz desordenada y engañosa que a menudo es motivo de infortunio.

¿Cuáles son exactamente sus requisitos de serialización? Puede haber mejores opciones … sin embargo, para muchos serializadores, una clase base sería más fácil que una interfaz. Por ejemplo, para XmlSerializer podría tener:

 [XmlInclude(typeof(MyObject))] // : ObjectBase [XmlInclude(typeof(MyObjectGroup))] // : ObjectBase public abstract class ObjectBase { /* */ } 

(el enfoque exacto depende del serializador)

En general, debe considerar interfaces como contratos que algunos tipos implementan y clases abstractas como nodos en la jerarquía de herencia que no existen por sí mismos (es decir, existe una relación “es una” entre la clase derivada y la clase abstracta base). Sin embargo, en la práctica, es posible que necesite utilizar interfaces en otros casos, como cuando necesita herencia múltiple.

Por ejemplo, IXmlSerializable no es una “entidad” en sí misma. Define un contrato que una entidad puede implementar. Las interfaces viven “fuera” de la jerarquía de herencia.

Una interfaz le permitirá definir un ‘contrato’ que el objeto deberá cumplir entregando propiedades y métodos como se describe en la interfaz. Puede hacer referencia a los objetos por variables de tipo interfaz, lo que puede causar cierta confusión sobre qué se ofrece exactamente.

Una clase base ofrece la oportunidad de construir un ‘árbol’ de herencia donde las clases más complejas (de un ‘tipo’ común) se construyen sobre los cimientos de unas clases ‘base’ más simples. El ejemplo clásico y molesto en OO es normalmente una clase base de ‘Shape’ y que es heredado por Triangle, Square, etc.

El punto principal es que con una interfaz debe proporcionar el contrato completo con cada clase que lo implementa, con un árbol de herencia (clases base) solo está cambiando / agregando las propiedades y métodos que son exclusivos de la clase secundaria, propiedades comunes y los métodos permanecen en la clase base.

En su ejemplo anterior, haría que el objeto ‘MyObjectGroup’ heredara la clase base ‘MyObject’, no se puede obtener nada de una interfaz aquí que pueda ver.

Hay dos cosas en la mente de Architect al diseñar clases.

  1. Comportamiento de un objeto.
  2. implementación del objeto.

Si una entidad tiene más de una implementación, entonces separar el comportamiento de un objeto de su implementación es una de las claves para el mantenimiento y el desacoplamiento. La separación puede lograrse por clase abstracta o por interfaz, pero ¿cuál es la mejor? Tomemos un ejemplo para verificar esto.

Tomemos un escenario de desarrollo donde las cosas (solicitud, modelo de clase, etc.) cambian con mucha frecuencia y debe entregar ciertas versiones de la aplicación.

Declaración inicial del problema : debe crear una clase “Tren” para el ferrocarril indio que tenga un comportamiento de maxSpeed ​​en 1970.

1. Modelado de negocios con clase abstracta

V 0.0 (Problema inicial) Declaración inicial del problema: debe crear una clase de Train para ferrocarril indio que tenga un comportamiento de maxSpeed ​​en 1970.

 public abstract class Train { public int maxSpeed(); } 

V 1.0 (Problema modificado 1) statement de problema modificado: Debe crear una clase de Diesel Train para ferrocarril indio que tenga un comportamiento de maxSpeed ​​en 1975.

 public abstract class DieselTrain extends train { public int maxFuelCapacity (); } 

V 2.0 (Problema modificado 2) Declaración de problema modificada: debe crear una clase ElectricalTrain para ferrocarril indio que tenga un comportamiento de maxSpeed, maxVoltage en 1980.

 public abstract class ElectricalTrain extends train { public int maxvoltage (); } 

V 3.0 (problema cambiado 3)

Declaración de problema modificada: debe crear una clase HybridTrain (utiliza diesel y electrcity) para el ferrocarril indio, que tiene un comportamiento de maxSpeed, maxVoltage, maxVoltage en 1985.

 public abstract class HybridTrain extends ElectricalTrain , DisealTrain { { Not possible in java } } {here Business modeling with abstract class fails} 

2. Business Modeling con interfaz

Simplemente cambie abstract palabra abstract a la interface y … su Business Modeling con interfaz tendrá éxito.

http://javaqna.wordpress.com/2008/08/24/why-the-use-on-interfaces-instead-of-abstract-classes-is-encouraged-in-java-programming/

Interfaz: si sus clases secundarias deberían implementar un determinado grupo de métodos / funcionalidades, pero cada una de las clases secundarias es libre de proporcionar su propia implementación, entonces use interfaces.

Por ejemplo, si está implementando una jerarquía de clases para vehículos, implemente una interfaz llamada Vehículo que tenga propiedades como Color MaxSpeed, etc. y métodos como Drive (). Todas las clases secundarias como Car Scooter AirPlane SolarCar, etc. deben derivarse de esta interfaz base pero proporcionan una implementación separada de los métodos y propiedades expuestos por Vehicle.

-> Si desea que sus clases secundarias implementen múltiples funciones no relacionadas en pocas interfaces de uso de herencia múltiple.

Por ejemplo, si está implementando una clase llamada Nave Espacial que tiene que tener funcionalidades de un Vehículo así como la de un OVNI, entonces haga Vehículo y OVNI como interfaces y luego cree una Nave Espacial de clase que implemente tanto Vehículo como OVNI.

Clases abstractas:

-> Cuando tenga un requisito en el que su clase base debe proporcionar la implementación predeterminada de ciertos métodos, mientras que otros métodos deben estar abiertos a ser reemplazados por clases secundarias, use clases abstractas.

Por ejemplo, nuevamente tome el ejemplo de la clase de Vehículo arriba. Si queremos que todas las clases derivadas de Vehicle implementen el método Drive () de una manera fija, mientras que los otros métodos pueden ser reemplazados por clases secundarias. En tal escenario implementamos la clase Vehicle como una clase abstracta con una implementación de Drive mientras dejamos los otros métodos / propiedades como abstractos para que puedan ser reemplazados por clases secundarias.

-> El objective de una clase abstracta es proporcionar una definición común de una clase base que múltiples clases derivadas puedan compartir.

Por ejemplo, una biblioteca de clases puede definir una clase abstracta que se usa como parámetro para muchas de sus funciones y requiere que los progtwigdores que usan esa biblioteca proporcionen su propia implementación de la clase creando una clase derivada.

En realidad podrías ir con AMBOS. ObjectBase le ahorra la molestia de implementar las propiedades comunes más de una vez e implementa IObject por usted. Donde sea que la uses, consulta IObject para que puedas hacer pruebas con burlas posteriores

Prefiero ir a la clase abstracta de base porque, teóricamente (bueno, es solo una teoría, no estoy probando ni diciendo que ninguna otra sea peor que esta), se deben usar interfaces, cuando se quiera mostrar, que algunas objeto es capaz de hacer algo (como IComparable – demuestras que cualquiera que lo implemente, se puede comparar con otra cosa), mientras que cuando tienes 2 instancias que solo comparten algo común o tienen 1 padre lógico – se deben usar clases abstractas.
También puede optar por ambos enfoques, utilizando la clase base, que implementará una interfaz, que señalará explícitamente lo que su clase puede hacer.

Todo lo demás es igual, ve con la interfaz. Es más fácil burlarse de las pruebas unitarias.

Pero en general, todo lo que uso para las clases base es cuando hay algún código común que prefiero poner en un lugar, en lugar de cada instancia de la clase derivada. Si es por algo como lo que describes, donde la forma en que se usan es la misma, pero sus mecanismos subyacentes son diferentes, una interfaz parece más apropiada.

He estado usando clases abstractas en mis proyectos, pero en proyectos futuros, usaré interfaces. La ventaja de “herencia múltiple” es extremadamente útil. Tener la capacidad de proporcionar una implementación completamente nueva de la clase, tanto en código como para fines de prueba, siempre es bienvenido. Por último, si en el futuro desea tener la capacidad de personalizar su código por desarrolladores externos, no tiene que darles su código real, pueden usar las interfaces …

Si tiene una función en clase, debe usar una clase abstact en lugar de la interfaz. En general, una interfaz se utiliza para ser en nombre de un tipo.

Tenga en cuenta que no puede anular operadores en Interfaces. Ese es el único problema real con ellos en lo que a mí respecta.

Elegir interfaces y clases abstractas no es una proposición cualquiera. Si necesita cambiar su diseño, conviértalo en una interfaz. Sin embargo, puede tener clases abstractas que proporcionan algún comportamiento predeterminado. Las clases abstractas son excelentes candidatos dentro de los marcos de aplicación.

Las clases abstractas te permiten definir algunos comportamientos; obligan a tus subclases a proporcionar a los demás. Por ejemplo, si tiene un marco de aplicación, una clase abstracta puede proporcionar servicios predeterminados, como el manejo de eventos y mensajes. Esos servicios permiten que su aplicación se conecte a su marco de aplicación. Sin embargo, hay algunas funcionalidades específicas de la aplicación que solo su aplicación puede realizar. Dicha funcionalidad puede incluir tareas de inicio y cierre, que a menudo dependen de la aplicación. Entonces, en lugar de tratar de definir ese comportamiento en sí, la clase base abstracta puede declarar el cierre abstracto y los métodos de inicio. La clase base sabe que necesita esos métodos, pero una clase abstracta le permite a su clase admitir que no sabe cómo realizar esas acciones; solo sabe que debe iniciar las acciones. Cuando es hora de iniciar, la clase abstracta puede llamar al método de inicio. Cuando la clase base llama a este método, Java llama al método definido por la clase secundaria.

Muchos desarrolladores olvidan que una clase que define un método abstracto también puede llamar a ese método. Las clases abstractas son una excelente forma de crear jerarquías de herencia planificadas. También son una buena opción para las clases sin hoja en las jerarquías de clase.

La definición de la clase abstracta puede describir código y estado, y las clases que derivan de ellos pueden no derivar de otras clases al mismo tiempo. Esa es la diferencia técnica.

Por lo tanto, desde el punto de vista del uso y la filosofía, la diferencia es que al configurar una clase abstracta, se restringe cualquier otra funcionalidad que los objetos de esa clase puedan implementar y se les proporciona a los objetos una funcionalidad básica que es común para cualquier clase. tal objeto (que también es un tipo de restricción), mientras que al configurar una interfaz, no configura restricciones para otras funcionalidades y no establece provisiones de código real para esa funcionalidad que usted tiene en mente. Use las clases abstractas cuando sepa todo lo que los objetos de esta clase deberían hacer para el beneficio de sus usuarios. Usa las interfaces cuando los objetos también puedan hacer algo más que ni siquiera puedes adivinar ahora.