Estoy refactorizando un sitio web PHP OOP heredado.
Estoy tan tentado de comenzar a usar 'final' en las clases para " make it explicit that the class is currently not extended by anything
". Esto podría ahorrar mucho tiempo si vengo a una clase y me pregunto si puedo cambiar el nombre / eliminar / modificar una protected
propiedad o método. Si realmente quiero extender una clase, puedo eliminar la palabra clave final para desbloquearla y extenderla.
Es decir, si vengo a una clase que no tiene clases para niños, puedo registrar ese conocimiento marcando la clase como final. La próxima vez que vaya, no tendría que volver a buscar la base de código para ver si tiene hijos. De este modo se ahorra tiempo durante las refactorizaciones.
Todo parece una idea sensata para ahorrar tiempo ... pero a menudo he leído que las clases solo deben hacerse 'finales' en ocasiones raras / especiales.
Tal vez arruina la creación de objetos simulados o tiene otros efectos secundarios en los que no estoy pensando.
¿Qué me estoy perdiendo?
fuente
Respuestas:
Quien escribió eso está mal. Use
final
generosamente, no hay nada de malo en eso. Documenta que una clase no se diseñó teniendo en cuenta la herencia, y esto suele ser cierto para todas las clases de forma predeterminada: diseñar una clase que se pueda heredar de manera significativa toma más que simplemente eliminar unfinal
especificador; Se necesita mucho cuidado.Por lo tanto, el uso
final
por defecto no es malo. De hecho, muchas personas proponen que este sea el valor predeterminado, por ejemplo, Jon Skeet .De hecho, esto es una advertencia, pero siempre puede recurrir a las interfaces si necesita burlarse de sus clases. Esto es ciertamente superior a hacer que todas las clases estén abiertas a la herencia solo con el propósito de burlarse.
fuente
final
desempeñaría un papel mucho más importante.Si desea dejarse una nota a sí mismo de que una clase no tiene subclases, hágalo y utilice un comentario, para eso están. La palabra clave "final" no es un comentario, y usar palabras clave de idioma solo para indicarle algo (y solo usted sabrá lo que significa) es una mala idea.
fuente
final
como se esperaba. No hay nada de malo en eso. Y usar una función de lenguaje para imponer una restricción siempre es superior a usar un comentario.final
debe indicar "No se debe crear ninguna subclase de esta clase" (por razones legales o algo así), no "esta clase actualmente no tiene hijos, por lo que todavía estoy seguro de meterme con sus miembros protegidos". La intenciónfinal
es la antítesis misma de "libremente editable", ¡y unafinal
clase ni siquiera debería tenerprotected
miembros!final
significa, "esta clase no se extenderá [por ahora]". Nada más, nada menos. Si PHP fue diseñado con esta filosofía en mente es irrelevante: después de todo, tiene lafinal
palabra clave. En segundo lugar, argumentar desde el diseño de PHP está destinado a fallar, dado lo patchworky y en general mal diseñado PHP.Hay un buen artículo sobre "Cuándo declarar las clases finales" . Algunas citas de ella:
PD: ¡Gracias a @ocramius por la excelente lectura!
fuente
"final" para una clase significa: ¿Quieres una subclase? Adelante, borra la subclase "final" tanto como quieras, pero no te quejes si no funciona. Estás sólo en esto.
Cuando una clase puede subclasificarse, el comportamiento en el que otros confían debe describirse en términos abstractos que las subclases obedecen. Las personas que llaman deben escribirse para esperar alguna variabilidad. La documentación debe ser escrita cuidadosamente; no puede decirle a la gente que "mire el código fuente" porque el código fuente aún no está allí. Eso es todo esfuerzo. Si no espero que una clase se subclasifique, es un esfuerzo innecesario. "final" dice claramente que este esfuerzo no se ha hecho y da una advertencia justa.
fuente
Una cosa que quizás no haya pensado es el hecho de que CUALQUIER cambio de una clase significa que debe someterse a nuevas pruebas de control de calidad.
No marques las cosas como finales a menos que realmente lo digas en serio.
fuente
final
(un cambio), entonces solo tengo que volver a probarla?final
? ¿Es esta experiencia de primera mano?final
clase tiene un caso de uso primario. Tiene clases polimórficas que no desea ampliar porque una subclase puede romper el polimorfismo. No lo use afinal
menos que deba evitar la creación de subclases. Aparte de eso, es inútil.El uso de 'final' le quita la libertad a otros que desean usar su código.
Si el código que escribe es solo para usted y nunca se dará a conocer al público ni a un cliente, puede hacer con su código lo que desee, por supuesto. De lo contrario, evita que otros construyan sobre su código. Demasiado a menudo tuve que trabajar con una API que hubiera sido fácil de ampliar para mis necesidades, pero luego me vi obstaculizado por 'final'.
Además, a menudo hay un código que mejor no se debe hacer
private
, peroprotected
. Claro,private
significa "encapsulación" y ocultar cosas consideradas como detalles de implementación. Pero como programador de API, también podría documentar el hecho de que el métodoxyz
se considera un detalle de implementación y, por lo tanto, puede modificarse / eliminarse en una versión futura. Por lo tanto, todos los que confíen en dicho código a pesar de la advertencia lo hacen bajo su propio riesgo. Pero en realidad puede hacerlo y reutilizar el código (con suerte ya probado) y encontrar una solución más rápido.Por supuesto, si la implementación de la API es de código abierto, uno solo puede eliminar el 'final' o hacer que los métodos estén 'protegidos', pero luego ha cambiado el código y necesita rastrear sus cambios en forma de parches.
Sin embargo, si la implementación es de código cerrado, se queda atrás para encontrar una solución o, en el peor de los casos, cambiar a otra API con menos restricciones con respecto a las posibilidades de personalización / extensión.
Tenga en cuenta que no encuentro que 'final' o 'privado' sean malos, pero creo que se usan con demasiada frecuencia porque el programador no pensó en su código en términos de reutilización y extensión de código.
fuente