¿Es un método de "inicio", "ejecución" o "ejecución" una buena práctica?

30

Actualmente estoy trabajando en una base de código que tiene muchas clases que implementan un método de Inicio. Esto me parece una construcción en dos fases, que siempre he considerado una mala práctica. No puedo decir la diferencia entre esto y un constructor.

¿Cuándo es apropiado usar un método de inicio en lugar de la construcción normal de objetos?

¿Cuándo debería preferir usar el constructor?

Editar: no creo que sea tan relevante, pero el lenguaje de programación es C #, podría aplicarse igualmente a Java o C ++

Dave Hillier
fuente
3
¿Podría agregar un poco más de contexto? ¿Idioma? Roscado vs hilo único? diferencia entre starty el constructor? etc ...
@MichaelT Puedo ver por qué preguntas, pero estoy interesado en el principio general detrás cuando es apropiado. Me preocupa que si di ejemplos específicos de la base de código en la que estoy trabajando, las respuestas se centrarían demasiado en los detalles y no en mis preguntas específicas.
Dave Hillier
2
@DaveHillier Por ejemplo, en Perl es una práctica estándar (y una buena) tener un initmétodo de algún tipo fuera de la newfunción: perldoc.perl.org/perlobj.html . Los modismos de un idioma pueden funcionar bien allí y no en otros idiomas.
1
Los ejemplos de clases con Startmétodos en API comunes incluyen subprocesos y cronómetros.
luiscubal
1
Cuente conmigo entre aquellos que necesitan una muestra de código para comprender lo que realmente está preguntando.
user16764

Respuestas:

44

Un Start()método (como Run(), Execute()o algo similar) es apropiado cuando el costo de construir el objeto es bajo, pero el costo de usarlo es alto. Por ejemplo: una clase que encapsula un algoritmo de optimización de la mejor ruta. Es trivial configurarlo con un conjunto de parámetros ( Xcuadrados por Ycuadrados, con tal método de evaluación), pero puede tardar un tiempo en ejecutarse. Si desea crear 20 de estos objetos, es posible que desee retrasar la ejecución hasta que se hayan creado todos, esto le permite paralelizarlos más fácilmente, por ejemplo.

Alternativamente, podría ser útil cuando no sabe cuándo será necesario iniciar el objeto, tal vez porque se basa en la entrada del usuario o en la lógica que selecciona de una lista de posibilidades.

Esto supone, por supuesto, que ese Start()es el método útil en el objeto, y no un equivalente a un Initialize()método. Si es solo una forma adicional de establecer más parámetros, no debería existir.

Bobson
fuente
1
Otro uso para un método de inicio es cuando la acción realizada también crea un nuevo subproceso de trabajo o un temporizador. El constructor no debe hacer este tipo de trabajo pesado ni generar efectos secundarios significativos (como crear un nuevo hilo).
Ziv
50

Code Complete (y muchos otros recursos de ingeniería de software) enfatiza la correspondencia de sus clases con objetos del mundo real. Creo que la razón fundamental de esto es que hace que sea más probable que tenga una verdadera comprensión de lo que está implementando, en lugar de atacar una idea intangible.

Si está suscrito a esta teoría, no veo nada de malo en agregar un Start()método a cualquier clase que, si fuera un objeto real, también tuviera un estado de reposo. Si no tiene sentido que su objeto exista mientras no se está ejecutando (o no tiene ningún sentido que su objeto se esté ejecutando), entonces diría que es una mala práctica.

Dan Albert
fuente
16
Una buena analogía Vale la pena señalar que Start()podría corresponder a un interruptor de encendido / apagado (como un interruptor de luz) que luego debería tener un Stop()botón pulsador (como el botón Imprimir en una máquina copiadora) donde se inicia y luego se ejecuta hasta que esté listo.
Bobson
3
+1 bien dicho y bienvenido a P.SE, respuestas como esta son un gran comienzo.
Jimmy Hoffa
14

Puede usar la inicialización diferida.

En la programación de computadoras, la inicialización diferida es la táctica de retrasar la creación de un objeto, el cálculo de un valor o algún otro proceso costoso hasta la primera vez que se necesita.

De esta forma, evita el acoplamiento temporal, lo que significa que el consumidor de su clase debe llamar a ciertos métodos en cierto orden. Tener que llamar start()primero es una forma de saber cómo funciona internamente la clase, lo cual es malo porque puede cambiar eso en el futuro.

Retrasar la costosa inicialización hasta que se necesite por primera vez

Ejemplo:

public class FooClass{

    private ExpensiveResource resource;
    private CheapResource cheap;

    public  FooClass(String someParameter){
        // constructor: initialize CheapResource cheap 
            // but NOT ExpensiveResource resource
    }

    public ExpensiveResource getExpensiveResource(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource
    }

    public String getExpensiveResourceName(){
        if (resource == null) {
            this.initializeExpensiveResource();     
        }
        return this.resource.getName();
    }   

    public CheapResource getCheapResource(){
        return this.cheap;
    }

    private initializeExpensiveResource(){
        // do expensive initialization of field "resource"
    }

}

public class Test{
    public static void main (String args[]){

        FooClass foo = new FooClass("some string");
        CheapResource cr = foo.getCheapResource();
        String s = foo.getExpensiveResourceName(); 
          // just now is the expensive resource initialized

    }
}
Tulains Córdova
fuente
55
Otro beneficio de la inicialización diferida que vale la pena señalar es que toma muy poco esfuerzo formarlo en un proxy virtual . Dependiendo de la situación, esto puede ser muy útil para mostrar algo mientras se espera que se cargue un recurso (especialmente útil para cosas como imágenes remotas). Basado en la pregunta original, no creo que esto sea en realidad lo que estaba buscando el OP, pero pensé que valía la pena mencionarlo.
Dan Albert
@DanAlbert tienes razón, no es lo que estaba pidiendo, pero sigue siendo interesante
Dave Hillier