class Square {
public static double width;
}
class Rectangle extends Square {
public static double height;
}Desde el punto de vista geométrico, un cuadrado es un rectángulo pero no al revés.
Si la herencia expresa una relación ontológica, Square hereda de Rectangle.
Desde el punto de vista de la API tiene sentido:
- Una función que recibe
Rectangleacepta tambiénSquare. - Una función que recibe
Squareno acepta unRectangle.
Desde el punto de vista de la implementación:
- El
Squaretienewidthyheightporque los hereda deRectangle, pero es redundante y fuente de bugs. - No hay que escribir implementaciones distintas para calcular el área del rectángulo.
Pero desde el punto de vista de los tipos de datos el rectángulo es un sub-tipo del cuadrado.
También se puede decir que el tipo Rectangle es "menor o igual" a Square.
Es menor porque todos los Rectangle son Square porque podemos ignorar el height,
pero no todos los Square son Rectangle.
Por eso también tiene sentido que Rectangle extends Square. El extends expresa esa relación
de "menor o igual" entre tipos.
Las consecuencias en la API serían:
- Una función que recibe
Rectangleno puede aceptar unSquare, pero es fácil convertir unSquarea unRectangle. - Una función que recibe un
Squarepuede aceptar unRectangley usar su ancho ignorando su alto. Esto es un poco confuso.
En este ejemplo no vale la pena usar herencia. Si fueran clases separadas, evitamos el problema (2).
Las consecuencias en la implementación son:
- El square se expresa sin redundancia, eliminando la posibilidad de toda una familia de bugs.
- Hay que escribir funciones distintas para calcular el área de un
Squarey de unRectangle, aunque también se puede tener solo la función paraRectangleya que es fácil convertir unSquarea unRectangle.