2016-04-15 36 views
10

Sto cercando un buon modello per il mio problema.C#, modelli - molte condizioni

devo alcune variabili bool:

condizione1, condizione2, condition3.

Anche io ho alcune azioni, che sono chiamati in luoghi diversi all'interno della classe:

azione1, azione2, Action3

Action1 viene chiamato quando le condizioni 1 e 2 sono vere. action2 viene chiamato quando le condizioni 2 e 3 sono vere. L'azione 3 viene chiamata quando tutte le condizioni sono vere.

Ovviamente questa è solo una semplificazione del problema. Non voglio usarlo se non altro in ogni posto. È terribilmente poco chiaro.

Ho pensato allo stato ma immagino che non sia la soluzione migliore per questo problema.

+0

Quindi vuoi una struttura logica, che, quando la esegui, segui le tue spiegazioni? Modelli – Mafii

+0

? Gli schemi di progettazione non sono accoppiamenti condizionali;) – Tushar

+1

crea un metodo statico che accetta quelle bool vars e restituisce l'azione corretta ... – Nino

risposta

12

Un'opzione è di avvolgere la logica di condizione in una classe base e quindi derivarne da essa per eseguire le azioni effettive. La è una variazione sul modello Command e (credo) il modello Strategy:

class ActionState 
{ 
    public bool Condition1{get;set;} 
    public bool Condition2{get;set;} 
    public bool Condition3{get;set;} 
} 

abstract class ActionDispatcher 
{ 
    protected abstract void ExecuteAction1(); 
    protected abstract void ExecuteAction2(); 
    protected abstract void ExecuteAction2(); 

    public void Action1(ActionState state) 
    { 
    if(state.Condition1 && state.Condition2) 
    { 
     ExecuteAction1(); 
    } 
    } 

    public void Action2(ActionState state) 
    { 
    if(state.Condition2 && state.Condition3) 
    { 
     ExecuteAction2(); 
    } 
    } 

    public void Action3(ActionState state) 
    { 
    if(state.Condition1 && state.Condition2 && state.Condition3) 
    { 
     ExecuteAction3(); 
    } 
    } 

    public void AllActions(ActionState state) 
    { 
    // Execute all actions depending on the state 
    Action1(state); 
    Action2(state); 
    Action3(state); 
    } 
} 
+1

Mi piacerebbe sapere chi ha downvoted una variazione di Command?Dobbiamo * davvero * scavare le copie GOF e fare riferimento a * pagine *? –

+0

@PanagiotisKanavos È GOF che vale la pena di leggere se sei uno sviluppatore C#? Ho visto che gli esempi sono solo in C++ (scusate se si è fuori tema) –

+0

Questo può essere reso più generico. Ad esempio, una singola classe potrebbe essere utilizzata. La condizione può diventare un campo '' Func ', l'azione un'azione . In effetti, questo è il numero di sistemi di flusso di lavoro (incluso WF). –

-1

Potrebbe essere un metodo di estensione:

public static void WhenTrue(this bool condition, Action action) 
{ 
    if (action == null) 
     throw new ArgumentNullException("action"); 

    if (condition) 
     action(); 
} 

Utilizzo:

(condition1 && condition2).WhenTrue(() => DoSomeWork(param1)); 

Ma questo solo ha senso quando si hanno molte condizioni e molte azioni per mantenere il codice più pulito.

+2

Come è meglio dire "if (condition1 && condition2) DoSomeWork (param1);'? – Sean

+2

Per essere onesti, non lo è. Tuttavia, se si cambia 'void' in' bool', allora sarebbe possibile incatenarsi ... Anche se è ancora abbastanza stupido :) Forse l'OP può pensare a qualcosa di base su quello =) –

3

Potrebbe essere aiutato da un enum con l'attributo [Flags], anziché i booleani separati. Vedi this answer per un'ottima spiegazione + esempi.

+9

Questo dovrebbe essere un commento –

0

È possibile implementare il modello visitatore. Ma dipende da voi l'astrazione di livello e le vostre functionnalities Visitor Pattern Implementation example

+0

Il pattern del visitatore è usato per alberi di oggetti, non vedo come sarebbe di aiuto qui –

+2

[Le risposte contengono solo collegamenti altrove "buone risposte"?] (http://meta.stackexchange.com/q/8231/158761) –

1

vostre condizioni non sono estremamente ben definiti, ma suona come una mappa degli Stati di azioni, in cui uno stato è definito da una serie di condizioni semplici, e ogni stato ha solo un'azione. Quindi, perché non rappresentarlo in questo modo?

Ecco un semplice esempio LINQPad:

void Main() 
{ 
    Dictionary<Cond, Action> d = new Dictionary<Cond, Action>() 
    { 
     { new Cond(waterproof:true, shockproof:true, freezeproof:false), delegate() { "Action1".Dump(); } }, 
     { new Cond(waterproof:false, shockproof:true, freezeproof:true), delegate() { "Action2".Dump(); } }, 
     { new Cond(waterproof:true, shockproof:true, freezeproof:true), delegate() { "Action3".Dump(); } } 
    }; 

    d[new Cond(true, true, false)](); 
    d[new Cond(false, true, true)](); 
    d[new Cond(true, true, true)](); 
} 

public class Cond : Tuple<bool, bool, bool> 
{ 
    public Cond(bool waterproof, bool shockproof, bool freezeproof) : base(waterproof, shockproof, freezeproof) 
    { 
    } 
} 

uscita:

Action1 
Action2 
Action3 

La sottoclasse di Tuple<> perché:

  1. Si rende tutto molto più leggibile piuttosto che avere il argomenti generici ovunque

  2. È possibile utilizzare i parametri denominati come ho fatto per rendere molto chiara la logica della mappa.

  3. È possibile scambiarlo con una classe personalizzata se è necessaria una logica più complessa, ad esempio un numero variabile di condizioni in ciascuno stato.

Si avrà probabilmente bisogno di ignorare Equals e GetHashCode in quel caso.

(È, ovviamente, non è necessario utilizzare i delegati anonimi, si può semplicemente passare un riferimento diretto al metodo che si desidera utilizzare)

0

C'è un modo è possibile implementare senza alcuna clausola if.

è possibile trasformare questo booleano in un intero, che consente di ottenere il metodo in un dizionario, per esempio:

cond1 = false, cond2 = true, cond3 = false

si può trasformare questo in: 0 + 1 + 0 = 1

poi, creerai una chiave per ogni soluzione che possiedi, come segue:

public Class Action1: IAction; 
public Class Action2: IAction; 
public Class Action3: IAction; 

Dictionary<int, IAction> dict = new Dictionary<int, IAction>() 
{ 
    6, new Action1(); //110 
    3, new Action2(); //011 
    7, new Action3(); //111 
}; 

IA Interfaccia ction:

public interface IAction 
{ 
    void execute(); 
} 

E dentro ogni metodo execute() in classe concreta, si implementare ogni azione.

Poi si eseguirà l'azione semplicemente:

key = //transform binary in decimal 
dict[key].execute(); 

Spero che questo aiuto.