2016-04-15 9 views
10

Ich suche ein gutes Muster für mein Problem.C#, Muster - viele Bedingungen

Ich habe einige Bool Variablen:

condition1, condition2, Bedingung3.

Auch habe ich einige Aktionen, die an verschiedenen Orten innerhalb der Klasse genannt werden:

action1, action2, action3

Action1 aufgerufen wird, wenn die Bedingungen 1 und 2 erfüllt sind. action2 wird aufgerufen, wenn die Bedingungen 2 und 3 wahr sind. Aktion 3 wird aufgerufen, wenn alle Bedingungen erfüllt sind.

Natürlich ist dies nur eine Vereinfachung des Problems. Ich möchte nicht anderswo verwenden. Es ist furchtbar unklar.

Ich habe über den Zustand nachgedacht, aber ich denke, es ist nicht die beste Lösung für dieses Problem.

+0

Sie wollen also eine logische Struktur, die, wenn Sie es ausführen, folgen Sie Ihren Erklärungen? – Mafii

+0

Muster? Entwurfsmuster sind keine bedingten Anweisungen mate;) – Tushar

+1

mache eine statische Methode, die diese bool vars nimmt und korrekte Action zurückgibt ... – Nino

Antwort

12

Eine Option besteht darin, die Bedingungslogik in eine Basisklasse zu verpacken und daraus abzuleiten, um die tatsächlichen Aktionen auszuführen. Das ist eine Variante des Command Muster und (glaube ich) das Strategy Muster:

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

    if (condition) 
     action(); 
} 

Nutzung::

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

Aber dies nur

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

Ich würde gerne wissen, wer eine Variation von Command abgelehnt hat?Müssen wir * wirklich * die GOF-Kopien ausgraben und auf * Seiten * verweisen? –

+0

@PanagiotisKanavos Ist GOF wirklich lesenswert, wenn Sie ein C# -Entwickler sind? Ich sah, dass die Beispiele nur C++ sind (Entschuldigung dafür, Off-Thema gehen) –

+0

Dies kann generischer gemacht werden. ZB könnte eine einzelne Klasse verwendet werden. Die Bedingung kann ein 'Func ' Feld oder eine Eigenschaft werden, die Aktion eine Aktion . In der Tat funktionieren so viele Workflow-Systeme (einschließlich WF). –

-1

Es ist eine Erweiterung Methode sein könnte, macht Sinn, wenn Sie viele Bedingungen und viele Aktionen haben, um den Code sauberer zu halten.

+2

Wie ist das besser zu sagen 'if (condition1 && condition2) DoSomeWork (param1); '? – Sean

+2

Um ehrlich zu sein, ist es nicht. Allerdings, wenn Sie 'void' in' Bool' ändern, dann wäre es möglich, zu verketten ... Obwohl immer noch ziemlich dumm :) Vielleicht kann das OP etwas auf der Basis denken, dass =) –

3

Ihnen könnte ein enum mit dem [Flags] Attribut anstelle von separaten booleans helfen. Siehe this answer für eine sehr gute Erklärung + Beispiele.

+9

Dies sollte ein Kommentar –

0

Sie könnten Besuchermuster implementieren. Aber es hängt von Ihnen ab Level Abstraktion und Ihre functionnalities Visitor Pattern Implementation example

+0

Besucher Muster ist für Bäume von Objekten verwendet, sehe ich nicht, wie es hier helfen würde –

+2

[Sind Antworten, die nur Links enthalten anderswo wirklich "gute Antworten"?] (http://meta.stackexchange.com/q/8231/158761) –

1

Ihre Bedingungen sind nicht enorm gut definiert, aber es klingt wie eine Karte von Staaten zu Maßnahmen, wenn ein Zustand, der durch eine Reihe von einfachen Bedingungen definiert ist, und jeder Zustand hat nur eine Aktion. Warum also nicht wirklich so darstellen?

Hier ist ein einfaches LinqPad Beispiel:

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) 
    { 
    } 
} 

Ausgang:

Action1 
Action2 
Action3 

Die Unterklasse von Tuple<> ist, weil:

  1. Es alles viel besser lesbar macht, anstatt die mit generische Argumente überall.

  2. Sie können benannte Parameter verwenden, wie ich getan habe, um die Kartenlogik sehr klar zu machen.

  3. Sie können es mit einer benutzerdefinierten Klasse austauschen, wenn Sie komplexere Logik benötigen, z. B. unterschiedliche Bedingungen in jedem Status.

Sie werden wahrscheinlich Equals und GetHashCode in diesem Fall außer Kraft setzen müssen.

(Sie offensichtlich brauchen nicht die anonyme Delegaten zu verwenden, können Sie einfach einen direkten Verweis auf die Methode übergeben Sie verwenden möchten)

0

Es gibt einen Weg Sie es ohne wenn Klausel umsetzen können.

Sie können diese boolean in einem Integer-Transformation, die die Methode in einem Wörterbuch, zum Beispiel bekommen kann:

cond1 = false, cond2 = true, cond3 = false

Sie dies in transformieren:

0 + 1 + 0 = 1

dann, Sie werden einen Schlüssel für jede Lösung, die Sie haben, wie folgt erstellen:

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 ction Schnittstelle:

public interface IAction 
{ 
    void execute(); 
} 

Und innerhalb jeder Methode execute() in konkrete Klasse, werden Sie jede Aktion umzusetzen.

Dann werden Sie Ihre Aktion, indem Sie einfach ausführen:

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

Hope this Hilfe.