Estoy escribiendo una solicitud y llegué a este punto:
private void SomeMethod()
{
if (Settings.GiveApples)
{
GiveApples();
}
if (Settings.GiveBananas)
{
GiveBananas();
}
}
private void GiveApples()
{
...
}
private void GiveBananas()
{
...
}
Esto se ve bastante sencillo. Hay algunas condiciones y, si son ciertas, se están llamando a los métodos. Sin embargo, estaba pensando, ¿es mejor hacerlo así?
private void SomeMethod()
{
GiveApples();
GiveBananas();
}
private void GiveApples()
{
if (!Settings.GiveApples)
{
return;
}
...
}
private void GiveBananas()
{
if (!Settings.GiveBananas)
{
return;
}
...
}
En el segundo caso, cada uno de los métodos se protege, por lo que incluso si alguno de esos métodos GiveApples
o GiveBananas
se llama desde afuera SomeMethod
, se ejecutarán solo si tienen el indicador correcto en Configuración.
¿Es esto algo que realmente debería considerar como un problema?
En mi contexto actual, es muy poco probable que esos dos métodos sean llamados desde fuera de este método, pero nadie puede garantizarlo.
design
conditions
Nikola
fuente
fuente
Respuestas:
Pienso en los guardias como algo que el método debe obedecer. En su ejemplo, el método no debe dar manzanas si Settings.GiveApples es falso.
Si ese es el caso, entonces el guardia definitivamente pertenece al método. Esto evita que lo llame accidentalmente desde otro punto de su aplicación sin consultar primero a los guardias.
Por otro lado, si la configuración solo se aplica al método de llamada, y otro método en otro lugar de su código puede dar GiveApples independientemente de la configuración, entonces no es una protección y probablemente debería estar en el código de llamada.
fuente
Coloque el protector dentro del método mismo. El consumidor de
GiveApples()
oGiveBananas()
no debe ser responsable de administrar a los guardias deGiveApples()
.Desde el punto de vista del diseño
SomeMethod()
, solo debe saber que necesita fruta y no debe preocuparse por lo que su aplicación debe hacer para obtenerla. La abstracción de la recuperación de fruta se vuelve permeable siSomeMethod()
es responsable de saber que existe un entorno global que permite la recuperación de cierta fruta. Esto cae en cascada si su mecanismo de protección cambia alguna vez, ya que ahora todos los métodos que necesitanGetApples()
oGetBananas()
necesitan ser refactorizados por separado para implementar esta nueva protección. También es muy fácil tratar de obtener fruta sin ese cheque mientras escribes el código.Lo que debe considerar en este escenario es cómo debe reaccionar su aplicación cuando la Configuración no permite que su aplicación dé frutos.
fuente
En general, a menudo es una buena idea separar las responsabilidades de probar algo como configuraciones proporcionadas externamente, y el "código comercial central" como
GiveApples
. Por otro lado, tener funciones que agrupen lo que pertenece también es una buena idea. Puede lograr ambos objetivos refactorizando su código de esta manera:Esto le brinda una mejor oportunidad de refactorizar el código
GiveApples
y / oGiveBananas
en un lugar separado sin ninguna dependencia de laSettings
clase. Obviamente, eso es beneficioso cuando desea llamar a esos métodos en una prueba unitaria que no le interesaSettings
.Sin embargo, si siempre está mal en su programa, bajo cualquier circunstancia, incluso en un contexto de prueba, llamar a algo como
GiveApples
fuera de un contexto dondeSettings.GiveApples
se verifica primero, y está bajo la impresión de que simplemente proporcionar una función comoGiveApples
sin laSettings
verificación es propensa a errores , luego se adhieren a la variante en la que se pruebaSettings.GiveApples
en el interior deGiveApples
.fuente