2008-12-09 28 views
6

A menudo quiero activar una determinada función solo una vez, pero necesito activarla desde otra función a la que se llama repetidamente. Por ejemplo, tomar una instantánea de algo para usarlo más tarde. Normalmente lo hago estableciendo un booleano global.¿Cómo activar una función una vez, y solo una vez ...?

Me pregunto si la forma en que lo hago es en realidad la mejor manera?

¡Me parece recordar que las variables globales son malas y las variables booleanas globales son incluso peores!

De todos modos, esta es la forma por lo general puedo lograr que provocó un cierto método sólo una vez:

En mi conjunto inicial de variables ...

private var myStatus:Boolean = false; 

Luego, dentro de la función que es llamada a menudo .. .

if (!myStatus) { 
    doMyFunction(); 
    myStatus = true; 
} 

parece bastante lógico para mí, pero es lo correcto ?

ACTUALIZACIÓN: Bueno, en base a lo que he aprendido de sus respuestas, en lugar de comprobar una variable booleana mundial, ahora en primer lugar comprobar si existe el nodo XML (estoy almacenar las imágenes dentro de una estructura XML antes de cualquier escritura para disco) y, si no lo hace, añado un nuevo nodo con los datos de imagen codificados en base64. Todavía configuro un indicador booleano para luego poder sobreescribir la imagen en blanco con los datos de imagen editados por el usuario si fuera necesario. Funciona perfectamente ¡Gracias por toda tu ayuda!

Ahora también me siento más cómodo con el uso de ese sistema particular (hilo inseguro) en ciertas situaciones.

Respuesta

7

Cuando se llama a una función que debe hacer lo que usted espera que haga con los argumentos que le des. Si llama a una función dos veces exactamente de la misma manera, debe esperar que esa función le proporcione los mismos resultados o haga lo mismo.

Probablemente es mejor para mover esta dependencia llamada una vez a la lógica que llama a su función muchas veces. Si solo necesita llamar a la función una vez, solo llámela una vez. Alternativamente, pase diferentes argumentos a la función para indicar que está haciendo algo diferente.

+0

Pero, ¿qué ocurre si la función devuelve el resultado de una declaración de caso y quieres que una de las declaraciones de casos pueda ejecutar una función? solo la primera vez que se devuelve? ¿O todavía no lo entiendo? – defmeta

+0

@defmeta: Creo que significa considerar por qué solo está ejecutando el código una vez. Si es para hacer la configuración, tal vez podrías simplificar moviendo la configuración a una etapa anterior. Si está almacenando en la memoria caché un resultado costoso que quizás nunca sea necesario, entonces, seguro, siga adelante y hágalo en el primer uso. –

+0

@defmeta: onebyone tiene razón, ¿tal vez podría ser un poco más específico sobre lo que debe hacer su función run-once? ¿Hay efectos secundarios al llamar a esta función? ¿Qué pasa si lo llamas dos veces? – rojoca

0

No veo nada malo con su enfoque aquí. Tenga en cuenta que no siempre es lo "correcto" ... Definitivamente hay cosas equivocadas, pero lo que es correcto puede ser subjetivo y también puede depender drásticamente en función de los requisitos del sistema.

0

No veo otra manera. Lo único que viene a la mente sobre cómo mejorar esto es la seguridad de los hilos. Pero eso solo es necesario si tienes varios hilos llamando a la función.

5

Realmente depende de a qué se refiere exactamente. Si su código será invocado desde más de un hilo, entonces usted tiene una condición de carrera que podría significar que doMyFunction podría ser llamado muchas veces. Esto se debe a que más de un hilo puede marcar myStatus, ver que es falso, luego invocar doMyFunction. Puede mejorar la situación un poco estableciendo la variable de primera:

if (!myStatus) { 
    myStatus = true; 
    doMyFunction(); 
} 

sino que sólo reduce la ventana de problemas, no lo elimina.

Para eliminar la condición de carrera, necesita un candado.

+0

Pues bien, este caso particular está dentro de una aplicación Flex bastante diseñada procesalmente, aunque la sentencia if es dentro de una declaración de caso/interruptor que posiblemente podría ser llamado dos veces si había neta seria congestión. Definitivamente moveré la variable setter hacia arriba. ¡Gracias! – defmeta

2

No es seguro para subprocesos. Puede que no le importe, pero dijo "agnóstico del lenguaje": probablemente no desee utilizar este patrón en una biblioteca de propósito general para Java.

Esta es una pregunta difícil de responder de una manera independiente del idioma, porque las alternativas disponibles dependen en gran medida del idioma. Por ejemplo, en POSIX tienes pthread_once si necesitas seguridad de hilos.En C tienes variables locales estáticas para sacar ese booleano del alcance global. En cualquier idioma OO, si está tomando una instantánea de "algo" para su uso posterior, entonces podría haber un objeto adecuado correspondiente al "algo" (o a la instantánea), que podría almacenar el indicador.

4

En C/C++ por lo general puede mantener el hecho de que doMyFunction() se llama una sola vez encapsulado mediante el uso de una variable estática, así:

void doMyFunction() { 
    // gets called only once. 
    // side effects go here. 
} 

void functionThatGetsCalledALot() { 
    static bool called = false; 
    if (!called) { 
     doMyFunction(); 
     called = true; 
    } 
    // do more stuff 
} 

Esto evita el uso de variables globales, pero tiene el mismo efecto, y la var estática se declara justo donde sea relevante, por lo que está claro lo que está sucediendo. Tenga en cuenta que esto no es seguro para subprocesos, por lo que necesitará un bloqueo si tiene subprocesos.

+0

Esto está mal, creo. Debe declarar "invocado" fuera de functionThatGetsCalledALot, de lo contrario, se llamará a doMyFunction cada vez y no una vez. – GeneCode

+0

No, es correcto. Ambos funcionan, pero usar una variable local estática es más limpia porque no se contamina el espacio de nombres global. ¿Realmente tratas de ejecutarlo? Busca variables locales estáticas: http://en.wikipedia.org/wiki/Local_variable#Static_local_variables – tgamblin

0

En Perl 5.10 o más adelante, se utiliza una variable state.

use 5.010; 

sub test{ 
    state $once = 1; 

    if($once){ 
    $once = undef; 
    say 'first'; 
    } else { 
    say 'not first'; 
    } 
} 

test for 1..5; 

salidas

 
first 
not first 
not first 
not first 
not first 
Cuestiones relacionadas