Το Σαββατοκύριακο είχα την ευκαιρία να σκεφτώ πάνω σ' αυτό το πρόβλημα πιο χαλαρά και κατέληξα σε ορισμένα συμπεράσματα που θέλω να μοιραστώ μαζί σας, μιας και άρχισε κι εμένα να με ενδιαφέρει αυτό το topic. Για να τα πάρουμε, όμως, τα πράγματα με τη σειρά.
Το πρώτο θέμα που πρέπει να επιλυθεί είναι η έκφραση των conditions. Με λίγη σκέψη εύκολα φτάνει κανείς στο συμπέρασμα ότι όλα τα conditions μπορούν να εκφραστούν σε στήλες και σειρές. Οι σειρές μπορεί να είναι AND συνθήκες και οι στήλες OR. Για παράδειγμα, το condition (A OR B) AND (C OR D) μετασχηματίζεται σε:
A AND C OR
A AND D OR
B AND C OR
B AND D
Ομοίως, το condition (A AND B) OR ((C AND D) OR E) μετασχηματίζεται ακόμα πιο εύκολα σε:
A AND B OR
C AND D OR
E
Από τα παραπάνω βγαίνει το συμπέρασμα, ότι το μόνο που χρειάζεται είναι ένας table editor εισαγωγής συνθηκών ο οποίος θα δέχεται τα AND σε σειρές και τα OR σε στήλες. Κάθε σειρά είναι true εάν και μόνο εάν όλες οι συνθήκες είναι true, ενώ η OR στήλη είναι true εάν και μόνο εάν μία σειρά είναι true. Με χρήση generics, αυτό μπορεί να γραφτεί ως εξής:
public enum Condition
{
EQ,NotEQ,LT,LTorEQ,GT,GTorEQ
}
//
// Σύγκριση μεταξύ δύο μεταβλητών...
//
public class Comparison<T> where T : IComparable<T>
{
private T lhs; // Left hand side
private T rhs; // Right hand side
private Condition cond;
private bool result;
public bool Result
{
get
{
this.result = this.ComparisonResult();
return result;
}
}
public Comparison(T lhs, T rhs, Condition cond)
{
this.lhs = lhs;
this.rhs = rhs;
this.cond = cond;
}
private bool ComparisonResult()
{
bool result = false;
//
switch (cond)
{
case Condition.EQ:
if (lhs.CompareTo(rhs) == 0) { result = true; }
break;
case Condition.NotEQ:
if (lhs.CompareTo(rhs) != 0) { result = true; }
break;
case Condition.GT:
if (lhs.CompareTo(rhs) > 0) { result = true; }
break;
case Condition.GTorEQ:
if (lhs.CompareTo(rhs) >= 0) { result = true; }
break;
case Condition.LT:
if (lhs.CompareTo(rhs) < 0) { result = true; }
break;
case Condition.LTorEQ:
if (lhs.CompareTo(rhs) <= 0) { result = true; }
break;
}
//
return result;
}
}
//
// Στο ComparisonRow όλα τα conditions είναι AND
//
public class ComparisonRow
{
private List<bool> rowResults = new List<bool>();
private bool result;
public bool Result
{
get
{
this.result = this.RowResult();
return result;
}
}
public void AddRowResult(bool comparisonResult)
{
this.rowResults.Add(comparisonResult);
}
private bool RowResult()
{
bool rowResult = true;
//
if (this.rowResults.Count == 0)
{
throw new Exception("No results entered in the comparison row...");
}
else
{
if (this.rowResults.Contains(false))
{
rowResult = false;
}
}
//
return rowResult;
}
}
//
// Στο ComparisonColumn όλα τα conditions είναι OR
//
public class ComparisonColumn
{
private List<bool> columnResults = new List<bool>();
private bool result;
public bool Result
{
get
{
this.result = this.ColumnResult();
return result;
}
}
public void AddColumnResult(bool rowResult)
{
this.columnResults.Add(rowResult);
}
private bool ColumnResult()
{
bool columnResult = false;
//
if (this.columnResults.Count == 0)
{
throw new Exception("No results entered in the comparison column...");
}
else
{
if (this.columnResults.Contains(true))
{
columnResult = true;
}
}
//
return columnResult;
}
}
Το επόμενο θέμα είναι η δομή IF THEN ELSE. Νομίζω ότι και αυτό μπορεί να λυθεί με την ισοδύναμη έκφραση του Immediate IF. Δηλαδή, IF (Condition, True part, False part). Από πλευράς editing ο χρήστης θα εισάγει τους περιορισμούς με τη μορφή ενός branching tree:
|---------------> ...
True |
|-------> Condition2 (ή RV)
| |
| |---------------> ...
Condition1
|
|
|-------> Condition3 (ή RV)
Όπου RV: Return Value, Condition(i): Οι συνθήκες που εισάγονται με μορφή πίνακα από τον προηγούμενο editor
Τέλος, απαιτείται η χρήση ενός equation editor ο οποίος θα κάνει evaluation σε expressions. Μάλιστα, οι τιμές των εξισώσεων μπορεί να είναι return values των conditions. Μια γενική μορφή του μπορεί να είναι η εξής:
Y variable: (ορίζεται από το χρήστη)
Equation: Panel αριθμών, τελεστών και συναρτήσεων:
+-----------------------------------------------+ +-----------------------+
|(3*x1+log(x2))*x3..... | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
+-----------------------------------------------+ +-----------------------+
Επιλογή μεταβλητών (μπορεί να είναι πεδία πινάκων):
+-----------------------------------------------+
|x1 x2 x3... |
| |
| |
| |
+-----------------------------------------------+
Σίγουρα μια τέτοια υλοποίηση είναι αρκετά πιο δύσκολο να επιτευχθεί σε σύγκριση με έναν απλό script editor τύπου notepad, αλλά αρκεί να γίνει μια φορά. Τα components είναι reusable και μπορούν να ενσωματωθούν εύκολα σε οποιαδήποτε μελλοντική εφαρμογή. Το evaluation δε των εκφράσεων με τον τρόπο αυτό γίνεται εύκολα. Όσο για expression evaluators έχει πήξει ο τόπος (βλπ. εδώ κι εδώ). Ο κώδικας του RangeEvaluator που έκανα post πιο πριν μπορεί να χρησιμοποιηθεί σαν μια ειδική περίπτωση του IF THEN ELSE. Πιστεύω ότι μια τέτοια υλοποίηση θα δουλέψει. Εσείς τι λέτε;
Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!