¡Cuando los métodos padre e hijo chocan!
TL;DR: Evite utilizar métodos privados en clases principales con nombres que las clases secundarias puedan usar.
Problemas
- La violación del principio de menor sorpresa
- Comportamientos inesperados y defectos
- Dependencias ocultas
- Extensibilidad limitada
- Ambigüedad del código
- Violación del principio abierto/cerrado
- Diseño engañoso
Soluciones
- Evitar jerarquías
- Cambiar el nombre de los métodos privados
- Mantener una nomenclatura clara
- Evite superponer nombres
- Evite los métodos protegidos
- Subclasificar para relaciones esenciales , no para reutilizar código
Contexto
Cuando se utiliza el mismo nombre de método en las clases padre e hija, se crea confusión.
Un método privado en la clase padre no se puede anular incluso si existe un método público con el mismo nombre en la clase hija.
Este es un problema que la mayoría de los lenguajes estáticos tienen en su diseño. Esta desconexión genera errores y dificulta el mantenimiento del código.
Código de muestra
Equivocado
<? class ParentClass { private function greet() { // This method is private return "Hello from ParentClass"; } public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { public function greet() { // Overriding a concrete method is a code smell // Compilers SHOULD warn you return "Hello from ChildClass"; } } $child = new ChildClass(); echo $child->callGreet(); // When callGreet() is invoked on the $child object, // it executes the following: // It calls $this->greet(), // which refers to the greet() method of ParentClass // because the original method is private // and cannot be overridden or accessed from ChildClass. // The unexpected output is 'Hello from ParentClass'
Bien
<? class ParentClass { protected function greet() { // notice the 'protected qualifier' return "Hello from ParentClass"; } public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { public function greet() { return "Hello from ChildClass"; } } $child = new ChildClass(); echo $child->callGreet(); // The output is "Hello from ChildClass" // This is the standard (and wrong) solution // Also fixed by most AIs
<? abstract class ParentClass { // Declare greet() as an abstract method // Following the template-method design pattern abstract protected function greet(); public function callGreet() { return $this->greet(); } } class ChildClass extends ParentClass { protected function greet() { return "Hello from ChildClass"; } } class OtherChild extends ParentClass { protected function greet() { return "Hello from OtherChild"; } } $child = new ChildClass(); echo $child->callGreet(); // Output: Hello from ChildClass $otherChild = new OtherChild(); echo $otherChild->callGreet(); // Output: Hello from OtherChild
Detección
- [x] Semiautomático
Puedes detectar este olor buscando métodos privados en las clases principales y verificando si las clases secundarias definen métodos con el mismo nombre. También debes probar los métodos principales que llaman a métodos privados.
Etiquetas
- Jerarquía
Nivel
- [x] Intermedio
¿Por qué es importante la biyección?
Un código claro y predecible debe reflejar la jerarquía del mundo real que modela.
Cuando se utilizan métodos privados con nombres superpuestos, se crea una brecha de biyección entre el modelo y la implementación.
Esta brecha confunde a los desarrolladores, aumenta los defectos y viola los principios del código limpio.
Generación de IA
Los generadores de IA suelen crear este olor cuando generan relaciones padre-hijo estándar.
Es posible que no verifiquen los niveles de acceso ni consideren las implicaciones de la herencia.
Detección de IA
Las herramientas de inteligencia artificial pueden solucionar este olor con instrucciones claras.
Puedes pedirle a la IA que verifique si hay nombres de métodos superpuestos y refactorice jerarquías.
¡Pruébalos!
Recuerde: los asistentes de IA cometen muchos errores
Sin instrucciones adecuadas | Con instrucciones específicas |
---|---|
Conclusión
Al diseñar clases padre e hijas, debe utilizar métodos que definan claramente la herencia y la accesibilidad.
Evite los métodos privados que se superponen con los métodos secundarios. Esto permite que su código sea legible, extensible y esté alineado con los principios del código limpio.
Lenguajes como Python permiten anular los métodos principales independientemente de sus nombres, mientras que Java aplica estrictamente los niveles de acceso.
C# se comporta de manera similar a Java . Estas diferencias implican que debes comprender las reglas específicas del lenguaje con el que estás trabajando para evitar comportamientos inesperados.
Relaciones
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxviii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-iii-t7h3zkv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-viii-8mn3352
Descargo de responsabilidad: los olores de código son mi opinión .
La herencia es buena, pero nunca debes olvidar que introduce un acoplamiento estrecho.
Robert C. Martín
Este artículo es parte de la serie CodeSmell en HackerNoon.