Ho una collezione di classi che modellano le espressioni logiche (booleane).
Esiste una classe astratta base LogicalExpression
e classi derivate: UnaryLogicalExpression
, BinaryLogicalExpression
, LogicalParameter
, LogicalValue
.
Alcuni esempi di codice
public abstract class LogicalExpression
{
public string[] parameterNames;
public abstract Boolean Evaluate(bool[] values);
}
public class BinaryLogicalExpression : LogicalExpression
{
public LogicalExpression LeftSide { get; set; }
public LogicalExpression RightSide { get; set; }
public LogicalOperator Operator { get; set; }
public override bool Evaluate(bool[] values)
{
bool leftSideResult = LeftSide.Evaluate(values);
bool rightSideResult = RightSide.Evaluate(values);
switch (Operator)
{
case LogicalOperator.And:
{
return leftSideResult && rightSideResult;
}
case LogicalOperator.Or:
{
return leftSideResult || rightSideResult;
}
case LogicalOperator.Xor:
{
return leftSideResult ^ rightSideResult;
}
default:
{
throw new InvalidOperationException("Operator not valid!");
}
}
}
public BinaryLogicalExpression(LogicalOperator Operator, LogicalExpression LeftSide, LogicalExpression RightSide)
{
this.Operator = Operator;
this.LeftSide = LeftSide;
this.RightSide = RightSide;
}
}
public class LogicalParameter : LogicalExpression
{
public int Index { get; set; }
public string Name { get; set; }
public override bool Evaluate(bool[] values)
{
try
{
return values[Index];
}
catch (IndexOutOfRangeException ex)
{
throw new IndexOutOfRangeException("The array of values must match the parameter list length!");
}
}
public LogicalParameter(int Index, string Name)
{
this.Name = Name;
this.Index = Index;
}
public override string ToString()
{
return Name;
}
}
Il problema / dillema qui è la classe LogicalParameter. Al momento è molto semplice, rappresenta una variabile booleana atomica, ma ho bisogno che faccia di più.
Voglio avere un'espressione logica che può avere parametri più complessi (non solo variabili booleane atomiche).
Ad esempio, ho un altro segmento di classe che implementa un'interfaccia ISegment. Qualsiasi tipo di ISegment può controllare se un profilo è associato a quel segmento.
public interface ISegment
{
bool CheckFor(Guid ProfileId);
}
Ora voglio mettere insieme questi due. Voglio avere un'espressione logica che può avere segmenti invece di variabili bool atomiche e quindi voglio valutarla fornendo un profiloId.
Qual è il modo migliore per farlo?
Potrei cambiare la classe LogicalExpression
, sovrascrivere Evaluate()
in modo che prenda un profileId invece di una matrice di valori e poi faccia ereditare le mie classi Segment da LogicalParameter. Ma questo è semplicemente orribile, non c'è separazione di preoccupazioni.
La mia classe LogicalExpression non ha bisogno di conoscere i segmenti giusto? Quindi, come dovrei affrontare questo? Ho la sensazione che sia qualcosa di molto semplice che mi manca.