Code:
public class Calc
{
private readonly NodeFactory m_NodeFactory;
public Calc()
{
m_NodeFactory = new NodeFactory();
m_NodeFactory.Register("+", typeof(AdditionNode));
m_NodeFactory.Register("*", typeof(MultiplicationNode));
}
public double Evaluate(string expression, out string output)
{
var node = m_NodeFactory.CreateNode(expression);
output = node.ToString();
return node.Evaluate();
}
}
public class NodeFactory
{
private readonly IDictionary<string, Type> m_OperationNodes;
public NodeFactory()
{
m_OperationNodes = new Dictionary<string, Type>();
}
public void Register(string operation, Type nodeType)
{
m_OperationNodes.Add(operation, nodeType);
}
public Node CreateNode(string expression)
{
string[] expressionValues = expression.Split(' ');
Node prevNode = null;
for (int i = expressionValues.Length-1; i >= 0; i--)
{
Type operationType;
if (!m_OperationNodes.TryGetValue(expressionValues[i], out operationType))
{
ValueNode vNode = new ValueNode(Convert.ToDouble(expressionValues[i]));
if (prevNode == null) prevNode = vNode;
else ((OperationNode)prevNode).Left = vNode;
continue;
}
OperationNode oNode = (OperationNode)Activator.CreateInstance(operationType);
oNode.Right = prevNode;
prevNode = oNode;
}
return prevNode;
}
}
public abstract class OperationNode : Node
{
public Node Left;
public Node Right;
}
public class AdditionNode : OperationNode
{
public override double Evaluate()
{
return Left.Evaluate() + Right.Evaluate();
}
public override string ToString()
{
return Left + " + " + Right;
}
}
public class MultiplicationNode : OperationNode
{
public override double Evaluate()
{
return Left.Evaluate() * Right.Evaluate();
}
public override string ToString()
{
return Left + " * " + Right;
}
}
public abstract class Node
{
public abstract double Evaluate();
}
public class ValueNode : Node
{
private readonly double m_Value;
public ValueNode(double value)
{
m_Value = value;
}
public override double Evaluate()
{
return m_Value;
}
public override string ToString()
{
return m_Value.ToString();
}
}
Test:
[TestFixture]
public class CalcTest
{
[TestCase("1 + 1", 2)]
[TestCase("1 + 1 + 2", 4)]
[TestCase("1 + 2 * 3", 7)]
[TestCase("1 + 2 * 3 * 4", 25)]
public void AdditionAndMultiplication(string value, double expected)
{
// arrange
var calc = new Calc();
// act
string actualText;
double actual = calc.Evaluate(value, out actualText);
// assert
Assert.AreEqual(expected, actual);
Assert.AreEqual(value, actualText);
}
}