2011-02-10 13 views
5

i potencialmente tener un conjunto de si las declaraciones que se ven así:simplify huge if statements - patrón de diseño?

if (a and b and c and d) { 
    // do stuff 
} else (!a and b and c and d) { 
    // do something else 
} else (!a and !b and c and D) { 
    // do yet something else 
} ... 

y así sucesivamente para todas las permutaciones posibles.

pensé en hacer esto:

switch ((a ? 'Y' : 'N') . (b ? 'Y' : 'N') . (c ? 'Y' : 'N') . (d ? 'Y' : 'N')) { 

    case 'YNYN': 
    // do stuff 
    break; 

    case 'NNNN': 
    // etc. 
    break; 

} 

hay una manera mejor?

+4

Use menos sentencias if. En serio, esta pregunta es tan vaga –

+1

bien no utilice el interruptor, por favor. –

+2

No creo que 'and' funcione aquí (dentro del interruptor). Use '.'? http: // codepad.org/X4fIQsSz – Dogbert

Respuesta

0

creo que usted debe considerar la solución de este problema con los árboles de decisión, en los diferentes nodos son posibles estados finales. luego puede componer su problema en un árbol, y deshacerse de todos estos ifs ....

0

Tomé un enfoque similar a la declaración de su caso una vez cuando necesitaba agregar datos en función de un conjunto de condiciones, de los cuales había cinco interruptores que podrían estar encendidos o apagados.

Para manejar la agregación de información sobre las posibles situaciones esto funcionó bien, pero fuera de ese caso de uso, si realmente hay n^2 acciones diferentes, entonces me quedaría con las múltiples declaraciones if. Si no hay muchas permutaciones, agruparé los resultados similares para disminuir la cantidad de ifs.

0

Sí, hay una manera mejor.

Oh, qué quieres más detalle que eso? Bueno, parece que tienes algún tipo de tabla de verdad con cuatro variables. ¿Hay 16 resultados posibles (2^4) o solo está interesado en un subconjunto? Si hay una variable que tiene un número aproximadamente igual de los resultados de cualquier manera, tal vez usar eso como su más alta si las declaraciones, y utilizar ifs anidados.

if (b) { 
    // cases where b is true 
    if (...) 
    ... 
} else { 
    // cases where b is false 
    if (...) 
    ... 
} 

También podría usar una declaración de cambio, pero en lugar de una cadena hecha de Y y N, use campos de bit.

7

Lo que probablemente haría (sin conocer los detalles) es crear una serie de clases para cada estado. A continuación, empuje el hacerTarea en esa clase:

class DoStuff { //The Client 
    protected $strategies = array(); 
    public function addStrategy(iDoStuffStrategy $strategy) { 
     $this->strategies[] = $strategy; 
    } 
    public function doStuff ($a, $b, $c, $d) { 
     foreach ($this->strategies as $strategy) { 
      if ($strategy->test($a, $b, $c, $d)) { 
       return $strategy->doStuff(); 
      } 
     } 
     throw new RuntimeException('Unhandleable Situation!'); 
    } 
} 

interface iDoStuffStrategy { 
    // Return a bool if you can handle this situation 
    public function test($a, $b, $c, $d); 
    // Execute the implementation 
    public function doStuff(); 
} 

Entonces, cada clase se vería así:

public function StrategyFoo implements iDoStuffStrategy { 
    public function test($a, $b, $c, $d) { 
     return $a && $b && $c && $d; 
    } 
    public function doStuff() { 
     //DoStuff! 
    } 
} 
public function StrategyBar implements iDoStuffStrategy { 
    public function test($a, $b, $c, $d) { 
     return !$a && $b && $c && $d; 
    } 
    public function doStuff() { 
     //DoStuff! 
    } 
} 

Se trata básicamente de una implementación de la Strategy Pattern. Hacerlo de esa manera te permite separar el árbol de decisiones.

+0

+1 Este enfoque o algo similar es lo que se necesita. Cada vez que tenga un conjunto largo de instrucciones de conmutación, probablemente sea mejor usar más pensamiento de estilo OOP. – NotMe

+0

@ircmaxwell ... Estoy intentando usar una versión de este código y tengo curiosidad si me falta algo. ¿Cómo agrega el método 'addStrategy' los objetos a la variable' $ strategy'? Realmente me encanta este patrón de diseño y me gustaría implementarlo, pero no puedo hacer que esa pieza funcione. – tollmanz

0

Trataría sus cuatro booleanos como cuatro bits, así como un entero entre 0 y 15. Crearía una matriz con 16 elementos y almacenaría un puntero de función en cada elemento de la matriz. Cada vez que usted necesita para hacer esto, yo evalúo los booleanos en un patrón de bits, convierte a int, y llamo el método almacenado en ese índice de la matriz.

Sé que estás preguntando sobre PHP, que me temo que no sé. En C#, podría hacer algo como esto:

static class Multiplexer 
{ 
    public static string Multiplex(bool a, bool b, bool c, bool d) 
    { 
     var i = 0; 
     i |= (a ? 1 : 0) << 3; 
     i |= (b ? 1 : 0) << 2; 
     i |= (c ? 1 : 0) << 1; 
     i |= (d ? 1 : 0); 
     return _functions[i](); 
    } 

    private static Func<string>[] _functions = new Func<string>[] { 
     () => { return "pie";}, 
     () => { return "index 1"; }, 
     () => { return DateTime.Now.ToString(); }, 
     () => { return "pie";}, 
     () => { return "index 1"; }, 
     () => { return DateTime.Now.ToString(); }, 
     () => { return Assembly.GetExecutingAssembly().FullName; }, 
     () => { return ""; }, 
     () => { return "pie";}, 
     () => { return "index 1"; }, 
     () => { return DateTime.Now.ToString(); }, 
     () => { return "pie";}, 
     () => { return "index 1"; }, 
     () => { return DateTime.Now.ToString(); }, 
     () => { return Assembly.GetExecutingAssembly().FullName; }, 
     () => { return ""; }}; 
}