Esperemos que no sea demasiado académico ...
Digamos que necesito números reales y complejos en mi biblioteca SW.
Basado en la relación is-a (o aquí ), el número real es un número complejo, donde b en la parte imaginaria del número complejo es simplemente 0.
Por otro lado, mi implementación sería que ese hijo extiende al padre, por lo que en el padre RealNumber tendría una parte real y el niño ComplexNumber agregaría arte imaginario.
También hay una opinión, que la herencia es malvada .
Recuerdo que ayer, cuando estaba aprendiendo OOP en la universidad, mi profesor dijo que este no es un buen ejemplo de herencia ya que el valor absoluto de esos dos se calcula de manera diferente (pero para eso tenemos una sobrecarga de métodos / polimorfismo, ¿verdad?). .
Mi experiencia es que a menudo usamos la herencia para resolver DRY, como resultado, a menudo tenemos clases abstractas artificiales en la jerarquía (a menudo tenemos problemas para encontrar nombres porque no representan objetos de un mundo real).
fuente
Respuestas:
Incluso si en un sentido matemático, un número real es un número complejo, no es una buena idea derivar real de complejo. Viola el Principio de sustitución de Liskov diciendo (entre otras cosas) que una clase derivada no debe ocultar las propiedades de una clase base.
En este caso, un número real tendría que ocultar la parte imaginaria del número complejo. Está claro que no tiene sentido almacenar un número de punto flotante oculto (parte imaginaria) si solo necesita la parte real.
Este es básicamente el mismo problema que el ejemplo de rectángulo / cuadrado mencionado en un comentario.
fuente
Esto no es realmente una razón convincente contra toda herencia aquí, solo el modelo
class RealNumber
<-> propuestoclass ComplexNumber
.Es posible definir una interfaz razonablemente
Number
, que tantoRealNumber
yComplexNumber
llevaría a cabo.Eso podría parecer
Pero luego querría restringir los otros
Number
parámetros en estas operaciones para que sean del mismo tipo derivado quethis
, al que puede acercarse conO, en cambio, usaría un lenguaje que permitiera el polimorfismo estructural, en lugar del subtipo de polimorfismo. Para el caso específico de los números, es posible que solo necesite la capacidad de sobrecargar operadores aritméticos.
fuente
Solución: no tener una
RealNumber
clase públicaMe resultaría totalmente correcto si
ComplexNumber
tuviera un método de fábrica estáticofromDouble(double)
que devolvería un número complejo con imaginario cero. Luego puede usar todas las operaciones que usaría en unaRealNumber
instancia en estaComplexNumber
instancia.Pero tengo problemas para ver por qué querrías / necesitarías tener una
RealNumber
clase pública heredada . Por lo general, la herencia se usa por estas razones (fuera de mi cabeza, corríjame si se perdió alguna)extendiendo el comportamiento.
RealNumbers
no puede hacer ninguna operación adicional que el número complejo no puede hacer, así que no tiene sentido hacerlo.implementando un comportamiento abstracto con una implementación específica. Como
ComplexNumber
no debe ser abstracto, esto tampoco se aplica.reutilización de código. Si solo usa la
ComplexNumber
clase, reutiliza el 100% del código.Implementación más específica / eficiente / precisa para una tarea específica. Esto podría aplicarse aquí,
RealNumbers
podría implementar algunas funcionalidades más rápido. Pero entonces esta subclase debería estar oculta detrás de la estáticafromDouble(double)
y no debería ser conocida afuera. De esta manera no necesitaría ocultar la parte imaginaria. Para el exterior solo debe haber números complejos (que son los números reales). También puede devolver esta clase privada RealNumber de cualquier operación en la clase de números complejos que dé como resultado un número real. (Esto supone que las clases son inmutables como la mayoría de las clases de números).Es como implementar una subclase de Integer que se llama Cero y codificar algunas de las operaciones ya que son triviales para cero. Puedes hacer esto, ya que cada cero es un número entero, pero no lo hagas público, escóndelo detrás de un método de fábrica.
fuente
Decir que un número real es un número complejo tiene más significado en matemáticas, especialmente en teoría de conjuntos, que en informática.
En matemáticas decimos:
Sin embargo, esto no significa que deba, o incluso deba, usar la herencia al diseñar su biblioteca para incluir una clase RealNumber y ComplexNumber. En Effective Java, Segunda edición de Joshua Bloch; El artículo 16 es "Composición de favor sobre herencia". Para evitar los problemas mencionados en ese elemento, una vez que haya definido su clase RealNumber, puede usarse en su clase ComplexNumber:
Esto le permite todo el poder de reutilizar su clase RealNumber para mantener su código SECO mientras evita los problemas identificados por Joshua Bloch.
fuente
Hay dos problemas aquí. La primera es que es común usar los mismos términos para los tipos de contenedores y los tipos de sus contenidos, especialmente con tipos primitivos como los números. El término
double
, por ejemplo, se usa para describir tanto un valor de coma flotante de doble precisión como un contenedor en el que se puede almacenar uno.La segunda cuestión es que, si bien las relaciones entre contenedores desde las que se pueden leer varios tipos de objetos se comportan de la misma manera que las relaciones entre los objetos mismos, las relaciones entre contenedores en los que se pueden colocar varios tipos de objetos se comportan de manera opuesta a las de su contenido . Cada jaula que se sabe que contiene una instancia de
Cat
será una jaula que contenga una instancia deAnimal
, pero no necesita ser una jaula que contenga una instancia deSiameseCat
. Por otro lado, cada jaula que puede contener todas las instancias deCat
será una jaula que puede contener todas las instancias deSiameseCat
, pero no necesita ser una jaula que pueda contener todas las instancias deAnimal
. El único tipo de jaula que puede contener todas las instanciasCat
y puede garantizarse que nunca contenga otra cosa que no sea una instancia deCat
, es una jaula deCat
. Cualquier otro tipo de jaula sería incapaz de aceptar algunas instancias de loCat
que debería aceptar, o sería capaz de aceptar cosas que no son instanciasCat
.fuente