2011-02-10 20 views
5

ho potenzialmente avere un insieme di istruzioni if ​​che assomigliano a questo:semplifica le dichiarazioni enormi se - modello di progettazione?

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 
} ... 

e così via per tutte le possibili permutazioni.

ho pensato di fare questo:

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

    case 'YNYN': 
    // do stuff 
    break; 

    case 'NNNN': 
    // etc. 
    break; 

} 

c'è un modo migliore?

+4

Utilizzare meno istruzioni if. Seriamente, questa domanda è così vaga –

+1

Beh, non usare l'interruttore, per favore. –

+2

Non penso che 'e' funzionerebbero qui (all'interno dell'interruttore). Usa '.'? http: // tastiera codici.org/X4fIQsSz – Dogbert

risposta

0

Penso che dovresti prendere in considerazione la risoluzione di questo problema con gli alberi decisionali, dove nodi diversi sono possibili stati finali. quindi puoi comporre il tuo problema su un albero e sbarazzarti di tutti questi ifs ....

0

Ho adottato un approccio simile alla tua dichiarazione caso una volta quando avevo bisogno di aggregare i dati in base a una serie di condizioni, di cui c'erano cinque interruttori che potevano essere accesi o spenti.

Per gestire l'aggregazione di informazioni sulle possibili situazioni, questo ha funzionato correttamente, ma al di fuori di tale caso d'uso, se ci sono veramente n^2 azioni diverse, allora rimango con le affermazioni multiple if. Se non ci sono davvero tante permutazioni, raggrupperei i risultati simili insieme per ridurre il numero di ifs.

0

Sì, c'è un modo migliore.

Oh, volevi più dettagli di così? Bene, sembra che tu abbia una sorta di tabella della verità con quattro variabili. Ci sono 16 possibili risultati (2^4), o sei interessato solo a un sottoinsieme? Se c'è una variabile che ha un numero approssimativamente uguale di risultati in entrambi i casi, forse la usi come istruzione if più in alto e usa ifs annidati.

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

È inoltre possibile utilizzare un'istruzione switch, ma anziché una stringa composta da Y e N utilizzare bitfield.

7

Quello che probabilmente farei (senza conoscere le specifiche) è creare una serie di classi per ogni stato. Quindi premere il doStuff su quella classe:

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(); 
} 

Poi, ogni classe sarebbe simile a questa:

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! 
    } 
} 

E 'fondamentalmente un'implementazione del Strategy Pattern. Facendolo in questo modo ti permette di separare l'albero decisionale.

+0

+1 Questo approccio o qualcosa di simile è ciò che è richiesto. Ogni volta che hai un lungo set di istruzioni switch è probabilmente meglio usare più stile di pensiero OOP. – NotMe

+0

@ircmaxwell ... Sto provando ad usare una versione di questo codice e sono curioso di sapere se mi manca qualcosa. In che modo il metodo 'addStrategy' aggiunge gli oggetti alla variabile' $ strategy'? Adoro questo modello di design e vorrei implementarlo, ma non riesco a far funzionare quella parte. – tollmanz

0

Tratterei i quattro valori booleani come quattro bit, quindi come un numero intero compreso tra 0 e 15. Creerei un array con 16 elementi e memorizzerei un puntatore a funzione in ciascun elemento dell'array. Ogni volta che devi farlo, valuterò i booleani in un pattern di bit, convertirò in int e chiamerò il metodo memorizzato in quell'indice dell'array.

So che mi stai chiedendo di PHP, che temo di non sapere. In C#, è possibile fare qualcosa di simile:

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 ""; }}; 
}