First the requirements:
- By management requirements, I can't use open source code.
- I need the users to define their own formulas for a project.
- My users don't know how to code.
- The formulas need to be saved somehow, and being read later.
- I need to debug the formulas written, so I need to be able to see and understand them.
- The formulas used are quite specialized and specific (actuarial formulas).
- Adding new formulas (functionality) must be done in fast and maintainable way.
What I did?
I implemented an abstract class let's say FormulaBase that all formulas inherit from:
Public MustInherit Class FormulaBase
Public MustInherit Function Formula(ByVal p as Parameters) as Result
Public MustInherit Function GetXML() as Text.StringBuilder
End Class
Then I created classes that wrapped the formulas like this:
Public Class SumFormula
Inherits FormulaBase
Public Shared ReadOnly Property XMLTag() As String
Get
Return "sum"
End Get
End Property
Private X As FormulaBase
Private Y As FormulaBase
Public Sub New(ByVal xmlText as Xml.XmlNode)
' Code to obtain read the sum parameters form XML.'
End Sub
Public Overrides Function Formula(ByVal p as Parameters) as Result
Return X.Formula(p) + Y.Formula(p)
End Function
Public Override Function GetXml() as Text.StringBuilder
Return New Text.StringBuilder().Append("<sum>").Append(X.GetXml()).Append(Y.GetXml()).Append("</sum>")
End Function
End Class
Then I created a factory to construct the formulas, like this:
Public NotInheritable Class FormulaFactory
Private Shared Formulas As Dictionary(Of String, Reflection.ConstructorInfo) = InitializeFormulas()
Private Shared Sub Add(ByVal collection As Dictionary(Of String, Reflection.ConstructorInfo), ByVal formula as Type)
' Some code to extract the contructor and XmlTag from each class and add them to the dictionary.'
End Sub
Private Shared Function InitializeFormulas() As Dictionary(Of String, Reflection.ConstructorInfo)
Dim Collection As New Dictionary(Of String, Reflection.ConstructorInfo)
Add(Collection, GetType(SumFormula))
Return Collection
End Sub
Public Shared Function ConstructFormula(xmlText as Xml.XmlNode) as FormulaBase
Return DirectCast(Formulas(xmlText).Invoke(New Object(){xmlText}), FormulaBase)
End Function
End Class
I use some more magic to showthe formulas to the users so they won't see the XML. To add anew formula i just need to create the wrapper class, add a Shared XMLTag property and a constructor that takes a XMLNode as parameter. Then I add a line to the FormulaFactory.InitializeFormulas method.
The question is, ¿Is there some other way I could have gone?