varias resueltos respuestas pruebas logicas funcion ejemplos condiciones con anidado anidada design design-patterns nested

design - resueltos - funcion si y



Tratar con instrucciones de cambio anidadas si en ese caso/anidadas (7)

¿Hay algún patrón de diseño / método / forma de eliminar las condiciones anidadas si entonces / condiciones?

Recuerdo encontrar algunos métodos utilizados por las personas de Google enumeradas en una publicación de blog del código de Google. Parece que no puede encontrarlo ahora, aunque



¿Has leído esto en el código de flecha de aplanamiento de Coding Horror?

Puedes reemplazar throw con return o goto si estás usando un idioma sin excepciones.


De hecho, escribí sobre cómo resolver estos problemas en mi blog en abril de 2008. Eche un vistazo aquí y dígame qué piensa.

Te recomiendo:

  1. Utilice el polimorfismo para obtener el comportamiento correcto en tiempo de ejecución que necesita sin declaraciones condicionales.

  2. Tome todas sus declaraciones condicionales y muévalas a un tipo de "fábrica" ​​que le proporcionará el tipo apropiado en tiempo de ejecución.

  3. Ya terminaste ¿No fue tan fácil? :)

Si desea ver un ejemplo de código real sobre cómo transformar su código, diríjase a mi blog.

PD: Este no es un intento barato de autopromoción; He sido un usuario de SO durante mucho tiempo, y esta es la primera vez que me he vinculado a mi blog, y solo lo he hecho porque creo que es relevante.


Desea utilizar una refactorización que reemplace un condicional utilizando una clase polimórfica. Por ejemplo .

O aquí hay otro ejemplo

Esencialmente, lo ideal es muy simple: crea una jerarquía de objetos y mueve los diversos comportamientos a un método modificado. Todavía necesitará un método para crear la clase correcta, pero esto se puede hacer usando un patrón de fábrica.

Editar

Permítanme agregar que esta no es una solución perfecta en todos los casos. Como (olvidé su nombre, lo siento) señaló en mis comentarios, algunas veces esto puede ser un dolor especialmente si tiene que crear un modelo de objeto solo para hacer esto. Esta refactorización es excelente si tienes esto:

function doWork(object x) { if (x is a type of Apple) { x.Eat(); } else if (x is a type of Orange) { x.Peel(); x.Eat(); } }

Aquí puede refactorizar el cambio a algún nuevo método que manejará cada fruta.

Editar

Como alguien señaló cómo se crea el tipo correcto para ir a DoWork, hay más formas de resolver este problema, entonces podría enumerar algunas de las formas básicas. La primera y más directa (y sí va contra el grano de esta pregunta) es un cambio:

class FruitFactory { Fruit GetMeMoreFruit(typeOfFruit) { switch (typeOfFruit) ... ... } }

Lo bueno de este enfoque es que es fácil de escribir, y suele ser el primer método que uso. Si bien todavía tiene una declaración de cambio está aislada de un área de código y es muy básica, todo lo que devuelve es un objeto. Si solo tiene un par de objetos y no están cambiando, esto funciona muy bien.

Otros patrones más convincentes que puedes mirar son una fábrica abstracta . También podría crear dinámicamente Fruit si su plataforma lo admite. También podría usar algo como el patrón de proveedor . Lo que esencialmente para mí significa que configuras tu objeto y luego tienes una fábrica que, según la configuración y una clave que le das a la fábrica, crea dinámicamente la clase correcta.


Es posible que desee ver el patrón de estrategia , en el que en lugar de poner una larga cadena de valores con condiciones vinculadas, abstrae cada condición a un objeto diferente, cada uno definiendo cuál es su comportamiento específico.

La clase que define esos objetos implementará una interfaz que será llamada por el objeto principal.


Qué tal si:

/* Code Block 1... */ if(/* result of some condition or function call */) { /* Code Block 2... */ if(/* result of some condition or function call */) { /* Code Block 3... */ if(/* result of some condition or function call */) { /* Code Block 4... */ } } }

Se convierte en esto:

/* Code Block 1... */ IsOk = /* result of some condition or function call */ if(IsOK) { /* Code Block 2... */ IsOk = /* result of some condition or function call */ } if(IsOK) { /* Code Block 3...*/ IsOk = /* result of some condition or function call */ } if(IsOK) { /* Code Block 4...*/ IsOk = /* result of some condition or function call */ } /* And so on... */

Por supuesto, puede regresar si alguna vez IsOk se convierte en falso, si corresponde.


No dice qué idioma está usando, pero si usa un lenguaje OO como C ++, C # o Java, a menudo puede usar funciones virtuales para resolver el mismo problema que está resolviendo actualmente con una declaración de switch , y de una manera más extensible. En el caso de C ++, compare:

class X { public: int get_type(); /* Or an enum return type or similar */ ... }; void eat(X& x) { switch (x.get_type()) { TYPE_A: eat_A(x); break; TYPE_B: eat_B(x); break; TYPE_C: eat_C(x); break; } } void drink(X& x) { switch (x.get_type()) { TYPE_A: drink_A(x); break; TYPE_B: drink_B(x); break; TYPE_C: drink_C(x); break; } } void be_merry(X& x) { switch (x.get_type()) { TYPE_A: be_merry_A(x); break; TYPE_B: be_merry_B(x); break; TYPE_C: be_merry_C(x); break; } }

con

class Base { virtual void eat() = 0; virtual void drink() = 0; virtual void be_merry() = 0; ... }; class A : public Base { public: virtual void eat() { /* Eat A-specific stuff */ } virtual void drink() { /* Drink A-specific stuff */ } virtual void be_merry() { /* Be merry in an A-specific way */ } }; class B : public Base { public: virtual void eat() { /* Eat B-specific stuff */ } virtual void drink() { /* Drink B-specific stuff */ } virtual void be_merry() { /* Be merry in an B-specific way */ } }; class C : public Base { public: virtual void eat() { /* Eat C-specific stuff */ } virtual void drink() { /* Drink C-specific stuff */ } virtual void be_merry() { /* Be merry in a C-specific way */ } };

La ventaja es que puede agregar nuevas clases derivadas de Base D , E , F , etc. sin tener que tocar ningún código que solo trate con punteros o referencias a Base , por lo que no hay nada que pueda desactualizarse de la forma en que switch declaración puede en la solución original. (La transformación se ve muy similar en Java, donde los métodos son virtuales por defecto, y estoy seguro de que también se ve similar en C #). En un proyecto grande, esta es una gran ganancia de mantenimiento.