Cerrado . Esta pregunta debe estar más
centrada . Actualmente no acepta respuestas.
Comentarios
Respuesta
El problema que he visto al mantener el código que utiliza indicadores es que el número de estados crece rápidamente y casi siempre hay estados sin controlar. Un ejemplo de mi propia experiencia: estaba trabajando en un código que tenía estas tres banderas
bool capturing, processing, sending;
Estos tres crearon ocho estados (en realidad, había otras dos banderas también). El código no cubría todas las posibles combinaciones de valores y los usuarios veían errores:
if(capturing && sending){ // we must be processing as well ... }
Resultó que había situaciones en las que la suposición en la declaración if anterior era falso.
Los indicadores tienden a agravarse con el tiempo y ocultan el estado real de una clase. Es por eso que deben evitarse.
Comentarios
Responder
Aquí hay un ejemplo cuando las banderas son útiles.
Tengo un fragmento de código que genera contraseñas (usando un generador de números pseudoaleatorios criptográficamente seguro). El llamador del método elige si o no la contraseña debe contener letras mayúsculas, minúsculas, dígitos, símbolos básicos, símbolos extendidos, símbolos griegos, cirílicos y unicode.
Con banderas, llamar a este método es fácil:
var password = this.PasswordGenerator.Generate( CharacterSet.Digits | CharacterSet.LowercaseLetters | CharacterSet.UppercaseLetters);
e incluso se puede simplificar a:
var password = this.PasswordGenerator.Generate(CharacterSet.LettersAndDigits);
Sin banderas, ¿cuál sería la firma del método?
public byte[] Generate( bool uppercaseLetters, bool lowercaseLetters, bool digits, bool basicSymbols, bool extendedSymbols, bool greekLetters, bool cyrillicLetters, bool unicode);
llamado así:
// Very readable, isn"t it? // Tell me just by looking at this code what symbols do I want to be included? var password = this.PasswordGenerator.Generate( true, true, true, false, false, false, false, false);
Como se indica en los comentarios, otro enfoque sería utilizar una colección:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LowercaseLetters, CharacterSet.UppercaseLetters, });
Esto es mucho más legible en comparación con el conjunto de true
y false
, pero todavía tiene dos inconvenientes:
El mayor inconveniente es que para permitir valores combinados, como CharacterSet.LettersAndDigits
escribirías algo así en el Generate()
método:
if (set.Contains(CharacterSet.LowercaseLetters) || set.Contains(CharacterSet.Letters) || set.Contains(CharacterSet.LettersAndDigits) || set.Contains(CharacterSet.Default) || set.Contains(CharacterSet.All)) { // The password should contain lowercase letters. }
posiblemente reescrito así:
var lowercaseGroups = new [] { CharacterSet.LowercaseLetters, CharacterSet.Letters, CharacterSet.LettersAndDigits, CharacterSet.Default, CharacterSet.All, }; if (lowercaseGroups.Any(s => set.Contains(s))) { // The password should contain lowercase letters. }
Compare esto con lo que tiene usando banderas:
if (set & CharacterSet.LowercaseLetters == CharacterSet.LowercaseLetters) { // The password should contain lowercase letters. }
El s segundo, un inconveniente menor es que no está claro cómo se comportaría el método si se llamara así:
var password = this.PasswordGenerator.Generate( new [] { CharacterSet.Digits, CharacterSet.LettersAndDigits, // So digits are requested two times. });
Comentarios
Respuesta
Un enorme bloque de funciones es el olor , no las banderas. Si coloca la bandera en la línea 5, entonces solo verifique la bandera en la línea 354, entonces eso es malo. Si coloca la bandera en la línea 8 y verifica la bandera en la línea 10, está bien. Además, uno o dos indicadores por bloque de código está bien, 300 indicadores en una función son malos.
Respuesta
Por lo general, indicadores se puede reemplazar completamente por algún tipo de patrón de estrategia, con una implementación de estrategia para cada valor posible de la bandera. Esto hace que agregar nuevos comportamientos sea mucho más fácil.
En situaciones críticas de rendimiento, el costo de la indirección podría emerger y hacer necesaria la deconstrucción en banderas claras. Dicho esto, «tengo problemas para recordar un solo caso en el que realmente tuve que hacer eso.
Responder
No, las banderas no son malas o un mal que debe ser refactorizado a toda costa.
Considere Java «s Pattern.compile (String regex, int flags) llamar. Esta es una máscara de bits tradicional y funciona. Eche un vistazo a las constantes en Java y dondequiera que vea un grupo de 2 n , sabrá que hay banderas allí.
En un mundo refactorizado ideal, uno usaría en su lugar un EnumSet donde las constantes son valores en una enumeración y como dice la documentación:
El rendimiento espacial y temporal de esta clase debe ser lo suficientemente bueno para permitir su uso como una alternativa de alta calidad y segura a los tradicionales «indicadores de bits» basados en int.
En un mundo perfecto, esa llamada de Pattern.compile se convierte en Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.
Todos dicho esto, sus banderas todavía.Es mucho más fácil trabajar con Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
de lo que sería tener Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
o algún otro estilo para tratar de hacer lo que realmente son las banderas y Bueno para.
Las banderas se ven a menudo cuando se trabaja con elementos del nivel del sistema. Al interactuar con algo en el nivel del sistema operativo, es probable que uno tenga una bandera en algún lugar, ya sea el valor de retorno de un proceso, los permisos de un archivo o las banderas para abrir un socket. Intentar refactorizar estas instancias en alguna cacería de brujas contra un olor de código percibido probablemente terminará con un código peor que si uno usara aceptado y entendido la bandera.
El problema ocurre cuando la gente hace un mal uso de las banderas lanzándolas juntas y creando un conjunto de frankenflag de todo tipo de indicadores no relacionados o tratando de usarlos donde no son indicadores en absoluto.
Respuesta
Estoy asumiendo que estamos hablando de banderas dentro de firmas de métodos.
Usar una sola bandera es suficientemente malo.
No significará nada para sus colegas la primera vez que lo vean. Tendrán que mirar el código fuente del método para establecer lo que hace. Probablemente estarás en la misma posición unos meses después, cuando olvides de qué se trata tu método.
Pasar una bandera al método, normalmente significa que su método es responsable de varias cosas. Dentro del método probablemente esté haciendo una simple verificación en las líneas de:
if (flag) DoFlagSet(); else DoFlagNotSet();
Esa es una mala separación de preocupaciones y normalmente puedes encontrar una forma de evitarla.
Normalmente tengo dos métodos separados:
public void DoFlagSet() { } public void DoFlagNotSet() { }
Esto tendrá más sentido con nombres de métodos que sean aplicables al problema que está resolviendo.
Pasar varios indicadores es dos veces peor. Si realmente necesita pasar varios indicadores, considere encapsularlos dentro de una clase. Incluso entonces, seguirá enfrentando el mismo problema, ya que su método probablemente esté haciendo varias cosas.
Responder
Banderas y la mayoría de las variables de temperatura tienen un olor fuerte. Lo más probable es que se puedan refactorizar y reemplazar con métodos de consulta.
Revisado:
Los indicadores y las variables temporales al expresar el estado, deberían refactorizarse a métodos de consulta. Los valores de estado (booleanos, ints y otras primativas) deberían casi siempre estar ocultos como parte de los detalles de implementación.
Los indicadores que se utilizan para el control, el enrutamiento y el flujo general del programa también pueden indicar el oportunidad de refactorizar secciones de las estructuras de control en estrategias o fábricas separadas, o lo que sea apropiado para la situación, que continúe haciendo uso de los métodos de consulta.
Respuesta
Cuando hablamos de banderas, debemos saber que se modificarán durante el tiempo de ejecución del programa y que afectarán el comportamiento del programa en función de sus estados. Siempre que tengamos un control preciso sobre estas dos cosas, funcionarán muy bien.
Las banderas pueden funcionar muy bien si
- Las ha definido en un ámbito apropiado. Por apropiado me refiero al alcance no debe contener ningún código que no necesite / no deba modificarlos. O al menos el código es seguro (por ejemplo, puede que no se llame directamente desde el exterior)
- Si es necesario manejar banderas desde afuera y si hay muchas banderas, podemos codificar el manejador de banderas como única forma para modificar banderas de forma segura. Este manejador de banderas puede encapsular banderas y métodos para modificarlas. Luego se puede convertir en singleton y luego se puede compartir entre las clases que necesitan acceso a las banderas.
- Y finalmente para la mantenibilidad, si hay demasiadas banderas:
- No es necesario decir que deberían seguir nombres razonables
- Debe documentarse con los valores válidos (puede ser con enumeraciones)
- Debe documentarse con QUÉ CÓDIGO MODIFICARÁ cada uno de ellos, y también con QUÉ CONDICIÓN resultará en la asignación de un valor particular a la bandera.
- QUÉ CÓDIGO LOS CONSUMIRÁ y QUÉ COMPORTAMIENTO resultará para un valor particular
Si hay un montón de banderas, un buen trabajo de diseño debe preceder, ya que las banderas comienzan a jugar un papel clave en el comportamiento del programa. Puede optar por diagramas de estado para modelar. Estos diagramas también funcionan como documentación y guía visual al tratar con ellos.
Siempre que estas cosas estén en su lugar, creo que no conducirán al desorden.
Respuesta
A partir de la pregunta asumí que el control de calidad se refería a variables de marca (globales) y no a bits de un parámetro de función.
Hay situaciones donde no tienes muchas otras posibilidades. Por ejemplo, sin un sistema operativo tienes que evaluar las interrupciones.Si se produce una interrupción con mucha frecuencia y no tiene tiempo para hacer una evaluación extensa en el ISR, no solo está permitido, sino que a veces incluso es una buena práctica establecer solo algunos indicadores globales en el ISR (debe dedicar el menor tiempo posible en el ISR), y para evaluar esos indicadores en su ciclo principal.
Respuesta
No creo que cualquier cosa es un mal absoluto en la programación, nunca.
Existe otra situación en la que las banderas pueden estar en orden, que no se mencionaron aquí todavía …
Considere el uso de cierres en este fragmento de Javascript:
exports.isPostDraft = function ( post, draftTag ) { var isDraft = false; if (post.tags) post.tags.forEach(function(tag){ if (tag === draftTag) isDraft = true; }); return isDraft; }
La función interna, que se está pasando al «Array.forEach», no puede simplemente «devolver verdadero».
Por lo tanto, debe mantener el estado afuera con una bandera.