--- title: Polymorphism with Abstract and Interface localeTitle: Polimorfismo con Resumen e Interfaz --- ## Polimorfismo con Resumen e Interfaz _Comparta y haga cumplir el código con Polymorphism usando la clase abstracta y la interfaz_ Profundizaremos en la Programación Orientada a Objetos e intentaremos pensar en términos de Patrones de Diseño para compartir y aplicar nuestro código utilizando Polimorfismo. ### Clase abstracta Digamos que tenemos una clase llamada Man con algunas propiedades ( `name` , `age` , `height` , `fav_drinks` y `fav_sports` ) y métodos ( `giveFirmHandshakes` , `beStubborn` y `notPutToiletPaper` ). ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } } ``` Necesitamos especificar nombre, edad y altura para crear una instancia de esta clase como lo requiere el constructor. ```php name, $jack->age, $jack->height); // => Jack - 26 - 5 Feet 6 Inches ``` Ahora, digamos que queremos agregar un nuevo método a esta clase llamada isActive. Este método verifica la propiedad activa y devuelve el mensaje apropiado según el valor de activo con el valor predeterminado de falso. Podemos establecerlo en verdadero para aquellos hombres que están activos. ```php active == true) { return "I am an active man."; } else { return "I am an idle man."; } } } $jack = new Man('Jack', '26', '5 Feet 6 Inches'); $jack->active = true; echo $jack->isActive(); // => I am an active man. $jake = new Man('Jake', '30', '6 Feet'); echo "\n" . $jake->isActive(); // => I am an idle man. ``` ¿Qué pasa si un hombre no está SOLO activo o inactivo? ¿Qué pasa si hay una escala de 1 a 4 que mide qué tan activo es un hombre? (1 - inactivo, 2 - ligeramente activo, 3- moderadamente activo, 4- muy activo)? Podemos tener un if..elseif..else declaraciones como esta: ```php active == 1) { return "I am an idle man."; } elseif ($this->active == 2) { return "I am a lightly active man."; } elseif ($this->active == 3) { return "I am a moderately active man."; } else { return "I am a very active man."; } } ``` Ahora, vamos a llevar esto un paso más allá. ¿Qué sucede si la propiedad activa de Man no es solo un número entero (1, 2, 3, 4, etc.)? ¿Qué pasa si el valor de activo es “atlético” o “perezoso”? ¿No tenemos que agregar más sentencias elseif buscando una coincidencia con esas cadenas? Se pueden usar clases abstractas para tal escenario. Con las clases abstractas, básicamente define la clase como abstracta y los métodos que desea aplicar como abstractos sin poner ningún código dentro de esos métodos. Luego crea una clase secundaria que extiende la clase abstracta principal e implementa los métodos abstractos en esa clase secundaria. De esta manera, aplicará todas las clases secundarias para definir su propia versión de métodos abstractos. Veamos cómo podemos configurar nuestro método `isActive()` como abstracto. # 1: Define la clase como abstracta. ```php isActive(); // => I am a very active athlete. ``` Completa la definición de la clase abstracta y el código de implementación ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } abstract public function isActive(); } class AthleticMan extends Man { public function isActive() { return "I am a very active athlete."; } } $jack = new AthleticMan('Jack', '26', '5 feet 6 inches'); echo $jack->isActive(); // => I am a very active athlete. ``` En este código, notará que el método abstracto `isActive()` se define dentro de la clase abstracta del `Man` y se implementa dentro de la clase infantil `AthleticMan` . Ahora la clase `Man` no puede ser instanciada directamente para crear un objeto. ```php isActive(); // => Fatal error: Uncaught Error: Cannot instantiate abstract class Man ``` Además, cada clase secundaria de la clase abstracta (clase `Man` ) necesita implementar todos los métodos abstractos. La falta de tal implementación resultará en un error fatal. ```php isActive(); // => Fatal error: Class LazyMan contains 1 abstract method // => and must therefore be declared abstract or implement // => the remaining methods (Man::isActive) ``` Al usar clases abstractas, puede imponer ciertos métodos para que sean implementados individualmente por las clases secundarias. ### Interfaz Hay otro concepto de Programación Orientada a Objetos que está estrechamente relacionado con las Clases Abstractas llamadas Interfaz. La única diferencia entre las clases abstractas y las interfaces es que en las clases abstractas, puede tener una combinación de métodos definidos ( `giveFirmHandshakes()` , `isStubborn()` , etc.) y métodos abstractos ( `isActive()` ) dentro de la clase principal mientras que en Interfaces, solo puede definir (no implementar) métodos dentro de la clase padre. Veamos cómo podemos convertir la clase abstracta de Man arriba en una interfaz. # 1: Defina la interfaz con todos los métodos (use la interfaz en lugar de la clase). ```php name = $name; $this->age = $age; $this->height = $height; } public function giveFirmHandshakes() { return "I give firm handshakes."; } public function beStubborn() { return "I am stubborn."; } public function notPutToiletPaper() { return "It's not humanly possible to remember to put toilet paper rolls when they are finished"; } public function isActive() { return "I am a very active athlete."; } } ``` # 3: instanciar la clase de implementación (AthleticMan) ```php isActive(); // => I am a very active athlete. ``` Con las interfaces, debes tener en cuenta que: * Los métodos no se pueden implementar dentro de la interfaz. * Las variables (propiedades) no se pueden definir dentro de la interfaz. * Todos los métodos definidos dentro de la interfaz deben implementarse en la clase secundaria (de implementación). * Todas las variables necesarias deben definirse dentro de la clase secundaria. * La interfaz Man aplica sus clases de implementación para implementar todos los métodos en la interfaz. Entonces, ¿cuál es el uso de interfaces? ¿No podemos simplemente crear una nueva clase AthleticMan y crear todos los métodos en lugar de implementar la interfaz? Aquí es donde entran en juego los _patrones de diseño_ . Las interfaces se usan cuando hay una clase base ( `Man` ) que quiere obligarte a hacer cosas (construir un objeto, giveFirmHandHakes, beStubborn, notPutToiletPaper y verificar si estás activo) pero no quiere decirte exactamente cómo hacerlo. . Puede seguir adelante y crear clases de implementación con implementaciones según lo considere conveniente. Mientras se implementen todos los métodos, a la interfaz `Man` no le importa cómo. Hemos repasado cómo y cuándo usar clases abstractas e interfaces en PHP. El uso de estos conceptos de OOP para tener clases con una funcionalidad diferente que comparten el mismo "plan" básico (clase abstracta o interfaz) se llama Polimorfismo.