Le describí a un colega por qué un constructor que llama a un método puede ser un antipatrón.
ejemplo (en mi oxidado C ++)
class C {
public :
C(int foo);
void setFoo(int foo);
private:
int foo;
}
C::C(int foo) {
setFoo(foo);
}
void C::setFoo(int foo) {
this->foo = foo
}
Me gustaría motivar mejor este hecho a través de su contribución adicional. Si tiene ejemplos, referencias de libros, páginas de blogs o nombres de principios, serían muy bienvenidos.
Editar: estoy hablando en general, pero estamos codificando en Python.
this
a cualquiera de los métodos que llame desde el constructor.Respuestas:
No ha especificado un idioma.
En C ++, un constructor debe tener cuidado al llamar a una función virtual, ya que la función real a la que llama es la implementación de la clase. Si es un método virtual puro sin una implementación, esto será una violación de acceso.
Un constructor puede llamar a funciones no virtuales.
Si su lenguaje es Java, donde las funciones son generalmente virtuales de manera predeterminada, tiene sentido que tenga que tener mucho cuidado.
C # parece manejar la situación de la manera que cabría esperar: puede llamar a métodos virtuales en constructores y llama a la versión más final. Entonces, en C # no es un antipatrón.
Una razón común para llamar a métodos desde constructores es que tiene múltiples constructores que desean llamar a un método "init" común.
Tenga en cuenta que los destructores tendrán el mismo problema con los métodos virtuales, por lo tanto, no puede tener un método de "limpieza" virtual que se encuentre fuera de su destructor y espere que sea llamado por el destructor de clase base.
Java y C # no tienen destructores, tienen finalizadores. No sé el comportamiento con Java.
C # parece manejar la limpieza correctamente a este respecto.
(Tenga en cuenta que aunque Java y C # tienen recolección de basura, eso solo administra la asignación de memoria. Hay otra limpieza que su destructor necesita hacer que no libera memoria).
fuente
Bien, ahora que la confusión con respecto a los métodos de clase frente a los métodos de instancia está aclarada, puedo dar una respuesta :-)
El problema no es llamar a métodos de instancia en general desde un constructor; es con la llamada a métodos virtuales (directa o indirectamente). Y la razón principal es que mientras está dentro del constructor, el objeto aún no está completamente construido . Y especialmente sus partes de subclase no se construyen en absoluto mientras se ejecuta el constructor de la clase base. Por lo tanto, su estado interno es inconsistente en una forma dependiente del idioma, y esto puede causar diferentes errores sutiles en diferentes idiomas.
C ++ y C # ya han sido discutidos por otros. En Java, se llamará al método virtual del tipo más derivado, sin embargo, ese tipo aún no se ha inicializado. Por lo tanto, si ese método usa algún campo del tipo derivado, es posible que esos campos aún no se inicialicen correctamente en ese momento. Este problema se discute en detalle en Effecive Java 2nd Edition , Artículo 17: Diseño y documento para herencia o de lo contrario lo prohíbe .
Tenga en cuenta que este es un caso especial del problema general de publicar referencias de objetos prematuramente . Los métodos de instancia tienen un
this
parámetro implícito , pero pasarthis
explícitamente a un método puede causar problemas similares. Especialmente en programas concurrentes en los que si la referencia del objeto se publica prematuramente en otro hilo, ese hilo ya puede invocar métodos antes de que finalice el constructor en el primer hilo.fuente
No consideraría que las llamadas a métodos aquí sean un antipatrón en sí mismo, más un olor a código. Si una clase proporciona un
reset
método, que devuelve un objeto a su estado original, entonces llamarreset()
al constructor es DRY. (No estoy haciendo ninguna declaración sobre los métodos de reinicio).Aquí hay un artículo que puede ayudarlo a satisfacer su apelación de autoridad: http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/
No se trata realmente de llamar a métodos, sino de constructores que hacen demasiado. En mi humilde opinión, llamar a métodos en un constructor es un olor que podría indicar que un constructor es demasiado pesado.
Esto está relacionado con lo fácil que es probar su código. Las razones incluyen:
Las pruebas unitarias implican mucha creación y destrucción, por lo tanto, la construcción debe ser rápida.
Dependiendo de lo que hagan esos métodos, puede ser difícil probar unidades de código discretas sin depender de alguna precondición (potencialmente no comprobable) configurada en el constructor (por ejemplo, obtener información de una red).
fuente
Filosóficamente, el propósito del constructor es convertir una parte bruta de memoria en una instancia. Mientras se ejecuta el constructor, el objeto aún no existe, por lo que llamar a sus métodos es una mala idea. Después de todo, es posible que no sepa lo que hacen internamente, y pueden considerar legítimamente que el objeto al menos existe (¡duh!) Cuando se les llama.
Técnicamente, puede que no haya nada de malo en eso, en C ++ y especialmente en Python, depende de usted tener cuidado.
Prácticamente, debe limitar las llamadas solo a los métodos que inicializan a los miembros de la clase.
fuente
No es un problema de propósito general. Es un problema en C ++, específicamente cuando se utilizan métodos virtuales y de herencia, porque la construcción de objetos ocurre al revés, y los punteros vtable se restablecen con cada capa de constructor en la jerarquía de herencia, por lo que si está llamando a un método virtual, es posible que no terminan obteniendo el que realmente corresponde a la clase que están tratando de crear, lo que anula el propósito de usar métodos virtuales.
En lenguajes con soporte de OOP sano, que establece el puntero vtable correctamente desde el principio, este problema no existe.
fuente
Hay dos problemas al llamar a un método:
No hay nada de malo en llamar a una función auxiliar, siempre que no se encuentre en los dos casos anteriores.
fuente
Yo no compro esto. En un sistema orientado a objetos, llamar a un método es prácticamente lo único que puede hacer. De hecho, esa es más o menos la definición de "orientado a objetos". Entonces, si un constructor no puede llamar a ningún método, ¿qué puede hacer?
fuente
En la teoría OOP, no debería importar, pero en la práctica, cada lenguaje de programación OOP maneja constructores diferentes . No uso métodos estáticos muy a menudo.
En C ++ y Delphi, si tuviera que dar valores iniciales a algunas propiedades ("miembros de campo"), y el código es muy extendido, agrego algunos métodos secundarios como extensión de los constructores.
Y no llame a otros métodos que hacen cosas más complejas.
En cuanto a los métodos "getters" y "setters" de propiedades, generalmente utilizo variables privadas / protegidas para almacenar su estado, además de los métodos "getters" y "setters".
En el constructor, asigno valores "predeterminados" a los campos de estado de propiedades, SIN llamar a los "accesores".
fuente