Como entendí la POO

Contexto de aprendizaje

Cuando escuché por primera vez el concepto de orientación a objetos fue en el año 2020, en mi primer año de educación superior como Ingeniero Informático.

En ese entonces ya había desarrollado algunos programas para escritorio con operaciones CRUD y bases de datos, utilizando Java como lenguaje de programación y MySQL como motor de base de datos.

A pesar de que ya tenía experiencia previa y buen entendimiento de los algoritmos y el enfoque “paso a paso” que se utiliza en programación, en un principio fue bastante dificil asimilar el concepto, no porque fuera dificil técnicamente hablando, sino porque en ese entonces, no entendía la razon de fondo de su utilización, y por ende los conceptos asociados como poliformismo, clases, herencias, y en general el ver todo como un “objeto”.

¿Porqué su uso y que ventajas tiene?

Como me gusta indagar mas allá de las herramientas que se entregaban en la institución educacional, decidí indagar y leer más acerca del paradigma y sobre todo, leer y ver ejemplos y comparaciones entre el enfoque tipo “cascada” que habia usado hasta ese entonces, versus el enfoque de “objetos” e interacción entre ellos.

Leí los clásicos ejemplos de Gatos y Perros que heredaban de una clase superior “Animal” y logré entender la razón de fondo por la que el paradigma de orientación a objetos fue creado en primera instancia, asi como también su amplio uso. La razón era muy simple : “Reutilización de código”.

Sin embargo seguí indagando más y me encontré con más razones, igual o más interesantes que la anterior, te las menciono a continuación:

1. Código más limpio y accesible

Esencialmente, al separar la lógica de negocio y de la aplicación en general en clases con sus propios atributos y métodos, estás escribiendo código mas limpio y accesible, ya que al declarar la clase, te limitas a utilizar la lógica que ya escribiste simplemente llamando a los métodos asociados, evitando así regar lógica duplicada por el código y además, permitiéndole a los demás miembros del equipo de desarrollo entender con mucha mayor facilidad, que es lo que está ocurriendo tras bambalinas, a diferencia de si tuvieran que ver un montón de funciones declaradas al inicio del código, cada vez que quisieran conocer como está funcionando el software.

Para ilustrar mejor lo mencionado, mantendré la tradición de explicarlo con Perros y Gatos. Supongamos que queremos representar su comportamiento y apariencia en un software. Utilizaremos PHP para representar las clases y las principales diferencias

Si utilizaramos el enfoque “clásico” sin objetos ni clases, tendríamos algo similar a lo siguiente:

    <?php
/* Primero la declaración de variables y métodos en lo más alto del código */
        $colorPerro = "Blanco";
        $tamanioPerro = "Mediano";
        $razaPerro = "Beagle";

        $colorPerro2 = "Negro";
        $tamanioPerro2 = "Pequeño";
        $razaPerro2 = "Chihuahua";

        function ladrar ($cantidad){
            for ( $i = 0;$i<$cantidad;$i++){
                echo ("guau\n");
            }
        }
/* Ahora lo mismo para los gatos */
        $colorGato = "Cafe";
        $tamanioGato = "Pequeño";
        $razaGato = "Angora";

        $colorGato2 = "Blanco";
        $tamanioGato2 = "Pequeño";
        $razaGato2 = "Siamés";

        function maullar ($cantidad){
            for ($i = 0;$i<$cantidad;$i++){
                echo ("miau\n");
            }
        }
   ?>

Luego si en algun momento quisieramos representar a los Perros y Gatos tendriamos lo siguiente:


    echo ("--Este Perro es un: {$razaPerro}, de color: {$colorPerro} y de tamaño: {$tamanioPerro}.\n");
    echo ("--Este Perro es un: {$razaPerro2}, de color: {$colorPerro2} y de tamaño: {$tamanioPerro2}.\n");
    echo ("--Este Gato es un: {$razaGato}, de color: {$colorGato} y de tamaño: {$tamanioGato}.\n");
    echo ("--Este Gato es un: {$razaGato2}, de color: {$colorGato2} y de tamaño: {$tamanioGato2}.\n");

Habrás notado que estamos repitiendo muchas instrucciones y siendo muy ineficientes al momento de crear y representar cada Gato y Perro como esperamos, ahora imagínate esto con Cien o más Perros y Gatos que queramos representar. ¿ilegible no?, es aquí donde entra el punto que te mencioné anteriormente de la reutilización que nos provee el paradigma de orientación a objetos, veamos como cambiaría el código implementando clases y objetos:

    <?php
/* Primero abstraemos lo que es común entre un Perro y un Gato, que puede ser reciclado. A esta abstracción la llamaremos clase Padre y estará en un fichero separado.*/
        abstract class Animal {
            
            private $color;
            private $tamanio;
            private $raza;
            private $tipo;

            public function __construct($color,$tamanio,$raza,$tipo){
                $this->color = $color;
                $this->tamanio = $tamanio;
                $this->raza = $raza;
                $this->tipo = $tipo;
            }

        /* Esto es el polimorfismo, multiples maneras de hacer algo, en este caso, ladrar o maullar */
            public abstract function onomatopeya($cantidad);

            public function describir () {
                echo ("--Este {$this->tipo} es un: {$this->raza}, de color: {$this->color} y de tamaño: {$this->tamanio}.");
            }

        }
   ?>
    <?php
/* Ahora es tan simple como extender de esta clase padre el hijo Perro y Gato, con sus características únicas en ficheros separados.*/
        class Perro extends Animal {
            
            
            public function __construct($color,$tamanio,$raza,$tipo){
                parent::__construct($color,$tamanio,$raza,$tipo);
            }

        /* Sobreescribimos la onomatopeya por la propia del perro */
            public function onomatopeya($cantidad){
                for ($i=0;$i<$cantidad;$i++){
                    echo ("guau\n");
                }
            }

        }
   ?>
    <?php
/* Ahora es tan simple como extender de esta clase padre el hijo Perro y Gato, con sus características únicas en ficheros separados.*/
        class Gato extends Animal {
            
            public function __construct($color,$tamanio,$raza,$tipo){
                parent::__construct($color,$tamanio,$raza,$tipo);
            } 

        /* Sobreescribimos la onomatopeya por la propia del Gato */
            public function onomatopeya($cantidad){
                for ($i=0;$i<$cantidad;$i++){
                    echo ("miau\n");
                }
            }

        }
   ?>

Ahora con estos tres ficheros separados, viene consigo el beneficio que menciona este punto, la legibilidad y accesibilidad del código mejorada, observa como cambia ahora la ejecución y representación de cada Animal:

    <?php
/* Requerimos los ficheros de Gato y Perro.*/
        require_once ("./Gato.php");
        require_once ("./Perro.php");

/* Ahora la representaccion de cada uno es tan simple como  */

    $beagle = new Perro ("Blanco","Mediano","Beagle","Perro");
    $chihuahua = new Perro ("Negro","Pequeño","Chihuahua","Perro");
    $angora = new Gato ("Cafe","Pequeño","Angora","Gato");
    $siames = new Gato ("Blanco","Pequeño","Siames","Gato");
    
/* Cada uno puede describirse con su método en comun "describir()" */
    $beagle->describir();
    $chihuahua->describir();
    $angora->describir();
    $siames->describir();

Notarás que hay algunas pequeñas cosas que siguen siendo redundantes, como la definición del tipo y el ciclo “for” redundante en la onomatopeya, esto se puede corregir también utilizando patrones de diseño, sin embargo eso es un mundo aparte y para mantener la simplicidad de la explicación se omitieron en este caso específico, sin embargo es un punto digno de mencionar.

2. Mejor mantenimiento y escalabilidad

Como verás, separamos la lógica en diversos lugares y con este mismo ejemplo podríamos escalar hasta donde queramos, concretamente creando mas Animales a conveniencia, heredando de la misma clase “Animal” tales como Pájaros, Serpientes, etc. Lo que facilita escalar en funcionalidad, así como el mantenimiento y cambios a realizar en las clases específicas, al estar centralizadas en un único lugar.

Conclusiones

Concluyendo, me atrevo a decir que la mejor forma de entender la orientación a objetos es con ejemplos sencillos siguiendo el enfoque de “Feynman”, si no lo conoces, es un método cuyo propósito es mejorar el entendimiento de conceptos nuevos, mediante una explicación sencilla utilizando el menor lenguaje técnico posible, así se puede entender el concepto base, y luego la terminología técnica asociada viene por añadido. Muchas gracias por leer.