¿Hay algún propósito para declarar un init()
método para un tipo?
No estoy preguntando si deberíamos preferir init()
a un constructor o cómo evitar declararinit()
.
Estoy preguntando si hay alguna razón para declarar un init()
método (ver qué tan común es) o si es un olor a código y debe evitarse.
El init()
idioma es bastante común, pero aún no he visto ningún beneficio real.
Estoy hablando de tipos que fomentan la inicialización a través de un método:
class Demo {
public void init() {
//...
}
}
¿Cuándo será esto útil en el código de producción?
Siento que puede ser un olor a código, ya que sugiere que el constructor no inicializa completamente el objeto, lo que resulta en un objeto creado parcialmente. El objeto no debería existir si su estado no está establecido.
Esto me hace creer que puede ser parte de algún tipo de técnica utilizada para acelerar la producción, en el sentido de las aplicaciones empresariales. Es la única razón lógica por la que puedo pensar en tener un idioma así, simplemente no estoy seguro de cómo sería beneficioso si es así.
init()
a la clase derivada, o viceversa?) Si es así, es un ejemplo de permitir que la clase base ejecute un "post-constructor "que solo se puede ejecutar después de que la clase más derivada haya terminado la construcción. Es un ejemplo de inicialización de múltiples fases.Respuestas:
Sí, es un olor a código. Un olor a código no es algo que necesariamente siempre deba eliminarse. Es algo que te hace echar un segundo vistazo.
Aquí tiene un objeto en dos estados fundamentalmente diferentes: pre-init y post-init. Esos estados tienen diferentes responsabilidades, diferentes métodos que se les permite llamar y diferentes comportamientos. Es efectivamente dos clases diferentes.
Si físicamente las convierte en dos clases separadas, eliminará estáticamente toda una clase de errores potenciales, a costa de que su modelo no coincida tan estrechamente con el "modelo del mundo real". Por lo general, el nombre del primero
Config
oSetup
o algo por el estilo.Así que la próxima vez, intente refactorizar sus modismos de inicio de construcción en modelos de dos clases y vea cómo resulta para usted.
fuente
this
al constructor es un olor a código y podría dar lugar a un código propenso a errores, y se recomienda evitarlo independientemente del dominio en el que se encuentre su proyecto).Depende.
Un
init
método es un olor a código cuando no es necesario separar la inicialización del objeto del constructor. A veces hay casos en los que tiene sentido separar estos pasos.Una búsqueda rápida en Google me dio este ejemplo. Puedo imaginar fácilmente más casos en los que el código ejecutado durante la asignación de objetos (el constructor) podría separarse mejor de la inicialización misma. Quizás tenga un sistema nivelado y la asignación / construcción se realice en el nivel X, pero la inicialización solo en el nivel Y, porque solo Y puede proporcionar los parámetros necesarios. Tal vez el "init" es costoso y debe ejecutarse solo para un subconjunto de los objetos asignados, y la determinación de ese subconjunto solo puede hacerse en el nivel Y. O desea anular el método (virtual) "init" en un derivado clase que no se puede hacer con un constructor. Tal vez el nivel X le proporciona objetos asignados de un árbol de herencia, pero el nivel Y no tiene conocimiento de la derivación concreta, solo de la interfaz común (donde
init
tal vez definido).Por supuesto, según mi experiencia, estos casos son solo un pequeño porcentaje del caso estándar en el que toda la inicialización se puede hacer directamente en el constructor, y cada vez que vea un
init
método separado , podría ser una buena idea cuestionar su necesidad.fuente
init
método. Sin embargo, cada vez que vea dicho método, no dude en cuestionar su necesidad.init()
método, estoy seguro de que me beneficiaría aprender sobre su propósito. Disculpe mi ignorancia, estoy asombrado de lo difícil que es encontrarle un uso, evitando que lo considere algo que debería evitarseMi experiencia se divide en dos grupos:
En mi experiencia personal, he visto solo algunas instancias de (1) pero muchas más instancias de (2). En consecuencia, generalmente asumo que init () es un olor a código, pero este no es siempre el caso. A veces no puedes evitarlo.
He descubierto que usar el Patrón de construcción a menudo puede ayudar a eliminar la necesidad / deseo de tener un init ().
fuente
init()
resolvería agregar un método? Elinit()
método necesitaría parámetros para aceptar dependencias, o tendría que instanciar las dependencias dentro delinit()
método, lo que también podría hacer con un constructor. ¿Podrías dar un ejemplo?Un escenario típico cuando un método Init es útil es cuando tiene un archivo de configuración que desea cambiar y tener el cambio en cuenta sin reiniciar la aplicación. Esto, por supuesto, no significa que un método Init deba llamarse por separado de un constructor. Puede llamar a un método Init desde un constructor, y luego llamarlo más tarde cuando / si cambian los parámetros de configuración.
Para resumir: como para la mayoría de los dilemas, ya sea que se trate de un olor a código o no, depende de la situación y las circunstancias.
fuente
Config
?update
/reload
probablemente sería más descriptivo para este tipo de comportamiento) para registrar realmente esos cambios . En ese caso, esa notificación haría que los valores de la configuración cambien internamente en su aplicación, lo que creo que podría observarse haciendo que su configuración sea observable, notificando a los observadores cuando se le dice a la configuración que cambie uno de sus valores. ¿O estoy malinterpretando tu ejemplo?Depende de cómo los uses.
Uso ese patrón en lenguajes recolectados de basura como Java / C # cuando no quiero seguir reasignando un objeto en el montón (como cuando estoy haciendo un videojuego y necesito mantener el rendimiento alto, los recolectores de basura matan el rendimiento). Utilizo el constructor para realizar otras asignaciones de almacenamiento dinámico que necesita y
init
para crear el estado útil básico justo antes de cada vez que quiera reutilizarlo. Esto está relacionado con el concepto de agrupaciones de objetos.También es útil si tiene varios constructores que comparten un subconjunto común de instrucciones de inicialización, pero en ese caso
init
serán privados. De esa manera, puedo minimizar cada constructor tanto como sea posible, por lo que cada uno solo contiene sus instrucciones únicas y una sola llamadainit
para hacer el resto.En general, sin embargo, es un olor a código.
fuente
reset()
método más descriptivo para su primera declaración? En cuanto al segundo (muchos constructores), tener muchos constructores es un olor a código. Asume que el objeto tiene múltiples propósitos / responsabilidades, lo que sugiere una violación de SRP. Un objeto debe tener una responsabilidad, y el constructor debe definir las dependencias requeridas para esa responsabilidad. Si tiene múltiples constructores debido a los valores opcionales, deben telescopios (que también es un olor a código, debería usar un constructor).string
lista de constructores de cualquier idioma , toneladas de opciones. Para mí, por lo general, son quizás 3 constructores como máximo, pero el subconjunto común de instrucciones como inicialización tiene sentido cuando comparten cualquier código pero difieren de alguna manera.String
, esto podría resolverse desacoplando la creación de cadenas. Al final, aString
es aString
, y su constructor solo debe aceptar lo que se necesita para que funcione según sea necesario. La mayoría de esos constructores están expuestos para fines de conversión, lo cual es un mal uso de los constructores. Los constructores no deben realizar la lógica, o corren el riesgo de una inicialización fallida, dejándolo con un objeto inútil.init()
Los métodos pueden tener bastante sentido cuando tiene objetos que necesitan recursos externos (como, por ejemplo, una conexión de red) que otros objetos utilizan simultáneamente. Es posible que no desee / necesite acaparar el recurso durante la vida útil del objeto. En tales situaciones, es posible que no desee asignar el recurso en el constructor cuando es probable que la asignación del recurso falle.Especialmente en la programación incrustada, desea tener una huella de memoria determinista, por lo que es una práctica común (¿buena?) Llamar a sus constructores temprano, tal vez incluso estático, y solo inicializar más tarde cuando se cumplen ciertas condiciones.
Aparte de tales casos, creo que todo debería ir a un constructor.
fuente
init
métodos es demasiado restrictivo, en mi humilde opinión.Generalmente prefiero un constructor que reciba todos los argumentos necesarios para una instancia funcional. Eso deja en claro todas las dependencias de ese objeto.
Por otro lado, uso un marco de configuración simple que requiere un constructor público sin parámetros e interfaces para inyectar dependencias y valores de configuración. Una vez hecho esto, el marco de configuración llama al
init
método del objeto: ahora que recibió todas las cosas que tengo para usted, realice los últimos pasos para prepararse para el trabajo. Pero tenga en cuenta: es el marco de configuración el que llama automáticamente al método init, por lo que no olvidará llamarlo.fuente
No hay olor a código si el método init () está semánticamente incrustado en el ciclo de vida del estado del objeto.
Si necesita llamar a init () para poner el objeto en un estado consistente, es un olor a código.
Hay varias razones técnicas por las que existe una estructura de este tipo:
fuente
El nombre init a veces puede ser opaco. Tomemos un auto y un motor. Para arrancar el automóvil (solo encender, escuchar la radio) desea verificar que todos los sistemas estén listos para funcionar.
Así que construyes un motor, una puerta, una rueda, etc., tu pantalla muestra engine = off.
No es necesario comenzar a monitorear el motor, etc., ya que todos son caros. Luego, cuando gira la llave para encender, llama motor-> inicio. Comienza a ejecutar todos los procesos caros.
Ahora ves engine = on. Y comienza el proceso de ignición.
El automóvil no se encenderá sin el motor disponible.
Puede reemplazar el motor con su cálculo complejo. Como una celda de Excel. No todas las celdas deben estar activas con todos los controladores de eventos todo el tiempo. Cuando te enfocas en una celda, puedes iniciarla. Aumentando el rendimiento de esa manera.
fuente