Codigo limpio y refactorización

Usa composición (delegación de comportamientos) en lugar de herencia para evitar acoplamiento rígido.

Composición y herencia son dos conceptos clave en la programación orientada a objetos para estructurar y organizar el código. Aunque la herencia tiene su lugar en ciertos escenarios, el principio de "preferir composición sobre herencia" (composition over inheritance) ayuda a crear sistemas más flexibles, reutilizables y desacoplados.

Ventajas de Usar Composición

  1. Evita Jerarquías Rígidas: No dependes de una estructura de herencia que puede volverse difícil de mantener.

  2. Reutilización: Los comportamientos (PuedeVolar, PuedeNadar) pueden ser usados por múltiples clases.

  3. Mayor Flexibilidad: Puedes cambiar o extender los comportamientos sin afectar a otras partes del sistema.

  4. Mantenibilidad: Las clases tienen responsabilidades claras y están desacopladas.


Cuándo Usar Composición en Lugar de Herencia

  1. Cuando una relación "tiene un" es más adecuada que "es un". Ejemplo: Un auto "tiene un" motor, no "es un" motor.

  2. Cuando quieres evitar métodos irrelevantes en las subclases. Ejemplo: Un pingüino no necesita un método volar.

  3. Cuando necesitas reutilización sin rigidez. Ejemplo: Comportamientos reutilizables como PuedeNadar o PuedeVolar.

  4. En sistemas que requieren flexibilidad y modularidad. Al usar composición, obtienes un diseño más modular, flexible y fácil de mantener, eliminando las limitaciones de las jerarquías de herencia rígidas. 😊


Diferencias Clave

AspectoHerenciaComposición
Relación"Es un" (is-a). Una clase hereda de otra."Tiene un" (has-a). Una clase contiene instancias de otras clases.
AcoplamientoAcopla fuertemente la clase hija a la clase base.Desacopla las clases, ya que los comportamientos se delegan a componentes.
ReutilizaciónLos métodos de la clase base se reutilizan, pero heredan toda su implementación.Permite reutilizar comportamientos específicos sin heredar implementaciones innecesarias.
EscalabilidadDifícil de cambiar si la jerarquía de clases crece mucho.Fácil de extender y modificar agregando o reemplazando componentes.
FlexibilidadPoco flexible, ya que las clases hijas dependen de la estructura base.Muy flexible, ya que los componentes pueden combinarse de muchas formas.

Código Malo

1class Motor {
2    public void arrancar() {
3        System.out.println("Motor arrancado");
4    }
5}
6
7// Subclase para coche eléctrico
8class CocheElectrico extends Motor {
9    @Override
10    public void arrancar() {
11        System.out.println("Motor eléctrico en marcha silenciosa");
12    }
13
14    public void cargarBateria() {
15        System.out.println("Cargando batería...");
16    }
17}
18
19// Subclase para coche de combustión
20class CocheCombustion extends Motor {
21    @Override
22    public void arrancar() {
23        System.out.println("Motor de combustión encendido");
24    }
25
26    public void llenarDeposito() {
27        System.out.println("Llenando el depósito de combustible...");
28    }
29}

Problema: Heredar Motor para un Coche es incorrecto.

Solución: Usa composición para manejar comportamientos específicos en lugar de herencia.

Código Bueno

1interface Motor {
2    void arrancar();
3}
4
5class MotorElectrico implements Motor {
6    @Override
7    public void arrancar() {
8        System.out.println("Motor eléctrico en marcha silenciosa");
9    }
10
11    public void cargarBateria() {
12        System.out.println("Cargando batería...");
13    }
14}
15
16class MotorCombustion implements Motor {
17    @Override
18    public void arrancar() {
19        System.out.println("Motor de combustión encendido");
20    }
21
22    public void llenarDeposito() {
23        System.out.println("Llenando el depósito de combustible...");
24    }
25}
26
27class Coche {
28    private Motor motor;
29
30    public Coche(Motor motor) {
31        this.motor = motor;
32    }
33
34    public void arrancarMotor() {
35        motor.arrancar();
36    }
37}
  • Loading...