Creo que el título "¿Indicadores de método como argumentos o como variables miembro?" puede ser subóptimo, pero como me falta algún atm de terminología mejor, aquí va:
Actualmente estoy tratando de entender el problema de si las banderas para un método de clase ( privado ) deben pasarse como argumentos de función o mediante una variable miembro y / o si hay algún patrón o nombre que cubra este aspecto y / o si esto sugiere algunos otros problemas de diseño.
Por ejemplo (el lenguaje podría ser C ++, Java, C #, realmente no importa en mi humilde opinión):
class Thingamajig {
private ResultType DoInternalStuff(FlagType calcSelect) {
ResultType res;
for (... some loop condition ...) {
...
if (calcSelect == typeA) {
...
} else if (calcSelect == typeX) {
...
} else if ...
}
...
return res;
}
private void InteralStuffInvoker(FlagType calcSelect) {
...
DoInternalStuff(calcSelect);
...
}
public void DoThisStuff() {
... some code ...
InternalStuffInvoker(typeA);
... some more code ...
}
public ResultType DoThatStuff() {
... some code ...
ResultType x = DoInternalStuff(typeX);
... some more code ... further process x ...
return x;
}
}
Lo que vemos arriba es que el método InternalStuffInvoker
toma un argumento que no se usa dentro de esta función, sino que solo se reenvía al otro método privado DoInternalStuff
. (Dónde DoInternalStuff
se utilizará de forma privada en otros lugares de esta clase, por ejemplo, en el DoThatStuff
método (público)).
Una solución alternativa sería agregar una variable miembro que lleve esta información:
class Thingamajig {
private ResultType DoInternalStuff() {
ResultType res;
for (... some loop condition ...) {
...
if (m_calcSelect == typeA) {
...
} ...
}
...
return res;
}
private void InteralStuffInvoker() {
...
DoInternalStuff();
...
}
public void DoThisStuff() {
... some code ...
m_calcSelect = typeA;
InternalStuffInvoker();
... some more code ...
}
public ResultType DoThatStuff() {
... some code ...
m_calcSelect = typeX;
ResultType x = DoInternalStuff();
... some more code ... further process x ...
return x;
}
}
Especialmente para cadenas de llamadas profundas donde el indicador de selección para el método interno se selecciona afuera, el uso de una variable miembro puede hacer que las funciones intermedias sean más limpias, ya que no necesitan llevar un parámetro de paso.
Por otro lado, esta variable miembro no representa realmente ningún estado de objeto (ya que no está establecida ni disponible fuera), sino que es realmente un argumento adicional oculto para el método privado "interno".
¿Cuáles son los pros y los contras de cada enfoque?
fuente
Respuestas:
Eso refuerza mi intuición al leer su pregunta: trate de mantener esta información lo más local posible, es decir, no la agregue al estado del objeto . Esto reduce el espacio de estado de su clase, haciendo que su código sea más fácil de entender, probar y mantener. Sin mencionar que evitar el estado compartido también hace que su clase sea más segura: esto puede o no ser una preocupación para usted en este momento, pero puede marcar una gran diferencia en el futuro.
Por supuesto, si necesita pasar estas banderas en exceso, puede convertirse en una molestia. En este caso, puede considerar
fuente
Definitivamente votaría por la opción "argumento" - mis razones:
Sincronización: ¿qué sucede si se llama al método desde varios subprocesos al mismo tiempo? Al pasar las banderas como argumento, no tendrá que sincronizar el acceso a estas banderas.
Capacidad de prueba: imaginemos que está escribiendo una prueba unitaria para su clase. ¿Cómo probará el estado interno del miembro? ¿Qué pasa si su código arroja una excepción y el miembro terminará en un estado inesperado?
Separación de preocupaciones: al agregar las banderas a los argumentos de su método, está claro que no se supone que otro método lo use. No lo usará por error en algún otro método.
fuente
La primera alternativa me parece bien. Se llama a una función con un parámetro, y hace algo que depende de ese parámetro . Incluso si solo reenvía el parámetro a otra función, lo hace esperando que el resultado dependa de alguna manera del parámetro.
La segunda alternativa se siente como usar una variable global, solo dentro del alcance de la clase en lugar del alcance de la aplicación. Pero es el mismo problema ... debes leer cuidadosamente todo el código de la clase para determinar quién y cuándo está leyendo y escribiendo esos valores.
Por lo tanto, la primera alternativa gana.
Si usaría demasiados parámetros (lea: dos o más) en la primera alternativa, que se pasan todos juntos a la siguiente función, puede considerar ponerlos en un objeto (conviértalo en una clase interna, si no es relevante para el resto de la aplicación) y usar este objeto como parámetro.
fuente
Quiero decir "ninguno".
En primer lugar, considere que ya sabe lo que va a hacer cuando llame
DoInternalStuff
. La bandera dice lo mismo. Así que ahora, en lugar de seguir adelante y hacerlo , te estás tirando pedos a una función que ahora tiene que decidir qué hacer.Si desea decirle a la función qué hacer, dígale qué hacer . Puede pasar una función real que desea ejecutar para cada iteración como un delegado de C # (o un objeto de función de C ++, o un Java ejecutable o similar).
C ª#:
Todavía terminas con la discusión pasando por todo el lugar, pero te deshaces de la mayoría de las tonterías de if / else
DoInternalStuff
. También puede almacenar el delegado como un campo si lo desea.En cuanto a si se debe pasar todo o guardarlo ... si tiene que elegir uno, entonces páselo. Es probable que almacenarlo te muerda el culo más tarde, ya que prácticamente has descuidado la seguridad del hilo. Tenga en cuenta que si tiene la intención de hacer algo con hilos, ahora tiene que bloquear durante toda la duración del ciclo, o alguien puede cambiar todo por debajo de usted. Mientras que si lo pasa, es menos probable que se tire a la basura ... y si aún necesita bloquear o algo, puede hacerlo durante una parte de una iteración en lugar de todo el ciclo.
Francamente, es bueno que sea molesto. Probablemente haya una forma mucho más simple de hacer lo que quieres hacer, que realmente no podría aconsejarte ya que el código obviamente no es real. La mejor respuesta varía según el caso.
fuente