Friday, May 24, 2013

Implementing Strategy Design Pattern in VBA

In this post, the main focus is on implementing Strategy Design Pattern. On a VBA side, we go through the use of VBA interface implementation mechanism.

Interface implementation

Here is a small example on using interface implementation mechanism in VBA. For this example, you need to insert three new Class Modules and one Standard module. Follow the instructions given here below.

Insert a new VBA Standard Module and copy-paste the following code:

Option Explicit
'
Sub tester()
    '
    ' We create an object which has a type of IInterface
    Dim obj As IInterface
    '
    ' Because ObjectOne implements IInterface, We
    ' can set this object to be ObjectOne
    Set obj = New ObjectOne
    obj.printMessage "Have a nice day!"
    '
    ' Because ObjectTwo also implements IInterface, We
    ' can set this object to be ObjectTwo
    Set obj = New ObjectTwo
    obj.printMessage "You too!"
    '
    ' We release the object
    Set obj = Nothing
End Sub
'
Insert a new VBA Class Module (name = IInterface) and copy-paste the following code:
 
Option Explicit
'
' interface to be implemented
Public Function printMessage(ByVal s As String)
End Function
'
 
Insert a new VBA Class Module (name = ObjectOne) and copy-paste the following code:

Option Explicit
'
Implements IInterface
'
Private Function IInterface_printMessage(ByVal s As String)
    Debug.Print "ObjectOne says " + s
End Function
'

Insert a new VBA Class Module (name = ObjectTwo) and copy-paste the following code:

Option Explicit
'
Implements IInterface
'
Private Function IInterface_printMessage(ByVal s As String)
    Debug.Print "ObjectTwo says " + s
End Function
'

We are done. If you run this program, it will print out the following two strings:

ObjectOne says Have a nice day!
ObjectTwo says You too!

What's happening here? We create first an interface. After that, we create two objects, both having the type IInterface because these objects are implementing IInterface. This means, that we could do the following:

Replace the existing VBA Standard Module and copy-paste the following code:

Option Explicit
'
Sub tester()
    '
    ' We create an object which has a type of IInterface
    Dim obj As IInterface
    '
    ' Because ObjectOne implements IInterface, We
    ' can set this object to be ObjectOne
    Set obj = New ObjectOne
    printOut "Have a nice day!", obj
    '
    ' Because ObjectTwo also implements IInterface, We
    ' can set this object to be ObjectTwo
    Set obj = New ObjectTwo
    printOut "You too!", obj
    '
    ' We release the object
    Set obj = Nothing
End Sub
'
Private Function printOut(ByVal message As String, ByRef obj As IInterface)
    obj.printMessage message
End Function
'

If you run this new main program, it will print out exactly the same two strings as before:

ObjectOne says Have a nice day!
ObjectTwo says You too!

However, in this new program we are witnessing interface-based polymorphism in action. PrintOut function in the previous code takes object having a type IInterface in its function interface. Since ObjectOne and ObjectTwo are both IInterface implementations, function accepts the both objects as inputs.

Strategy design pattern implementation in VBA

Before presenting the actual Strategy Pattern, I would like to present one motivational example, which can help us to understand in a more concrete way, what is the problem what we are trying to solve.

Design - before

Let us think, that we need to build a program to price a simple forward with the following requirement: we should be able to price a forward with or without given cashflow PV. How would you implement this in VBA? Let me present first, how I have been implementing this, before I got myself familiar with interface implementation.

Insert a new VBA Standard Module and copy-paste the following code:

Option Explicit
'
Sub tester()
    '
    ' create pricer for forward
    Dim pricer As New ForwardPricer
    Debug.Print pricer.price(100, 0.02, 1.25, ENUM_CASHFLOW_TYPE.none)
    Debug.Print pricer.price(100, 0.02, 1.25, ENUM_CASHFLOW_TYPE.discrete, 7.25)
    Set pricer = Nothing
End Sub
'

Insert a new VBA Class (name = ForwardPricer) Module and copy-paste the following code:

Option Explicit
'
Public Enum ENUM_CASHFLOW_TYPE
    none = 1
    discrete = 2
End Enum
'
Public Function price(ByVal spot As Double, ByVal yield As Double, ByVal maturity As Double, _
ByVal cashFlowType As ENUM_CASHFLOW_TYPE, Optional ByVal cashFlowPV As Double) As Double
    '
    Select Case cashFlowType
        '
        Case ENUM_CASHFLOW_TYPE.none
        price = spot * Exp(yield * maturity)
        '
        Case ENUM_CASHFLOW_TYPE.discrete
        price = (spot - cashFlowPV) * Exp(yield * maturity)
        '
    End Select
End Function
'

The previous program will print out prices for two different forwards. There is absolutely nothing wrong in this program. However, as soon as someone wants to add any new requirements for your pricer, you need to modify your ForwardPricer class and Enumerator. All in all, you will end up babysitting Enumerator and Select Case branches, when inserting any new pricing algorithm, for example.

If we think about pricing financial instrument, it's all about pricing algorithms which can vary. What if we could create a design, that could enable the addition of any new algorithm in a such a way, that we do not need to change anything in our existing classes?

Design - after

For this example, you need to insert four new Class Modules and two Standard modules. Follow the instructions given here below.

Insert a new VBA Standard Module and copy-paste the following code. This module is for Enumerator, which is going to be used for implementing parameter wrapper.

Option Explicit
'
Public Enum Var
    Spot
    Yield
    maturity
    CashflowPV
End Enum
'

Insert a new VBA Standard Module and copy-paste the following code. This our tester program.

Option Explicit
'
Sub tester()
    '
    Dim parameters As New Collection
    Dim p As Scripting.Dictionary
    '
    ' create a set of parameters
    Dim i As Integer
    For i = 1 To 20
        '
        Set p = New Scripting.Dictionary
        p.Add Var.Spot, 100
        p.Add Var.CashflowPV, 7.25
        p.Add Var.Yield, 0.02
        p.Add Var.maturity, 0.25 + (i - 1) * 0.25
        parameters.Add p
        Set p = Nothing
    Next i
    '
    ' use algorithm to price forward with cashflow PV
    Dim algorithm As IForward: Set algorithm = New Forward_DiscreteIncome
    Dim pricer As New ForwardEngine
    Dim prices_DiscreteIncome As Collection: Set prices_DiscreteIncome = pricer.execute(algorithm, parameters)
    Set parameters = Nothing
    '
    ' create another set of parameters
    For i = 1 To 20
        '
        Set p = New Scripting.Dictionary
        p.Add Var.Spot, 100
        p.Add Var.Yield, 0.02
        p.Add Var.maturity, 0.25 + (i - 1) * 0.25
        parameters.Add p
        Set p = Nothing
    Next i
    '
    ' use algorithm to price forward without cashflow PV
    Set algorithm = New Forward_NoIncome
    Dim prices_noIncome As Collection: Set prices_noIncome = pricer.execute(algorithm, parameters)
    Set parameters = Nothing
    '
    ' place debug point below this row and investigate your
    ' prices_DiscreteIncome and prices_noIncome collections Locals window
    Set p = Nothing
    Set prices_DiscreteIncome = Nothing
    Set prices_noIncome = Nothing
    Set pricer = Nothing
    Set algorithm = Nothing
End Sub
'

Insert a new VBA Class Module (name = IForward) and copy-paste the following code. This is the actual interface class.

Option Explicit
'
' Interface to be implemented
Public Function price(ByRef p As Scripting.Dictionary) As Double
End Function
'

Insert a new VBA Class Module (name = ForwardEngine) and copy-paste the following code.This is the class which uses concrete implementations.

Option Explicit
'
Public Function execute(ByRef algorithm As IForward, ByRef parameters As Collection) As Collection
    '
    Dim result As New Collection
    Dim i As Long
    For i = 1 To parameters.Count
        Dim price As Double: price = algorithm.price(parameters.Item(i))
        result.Add price
    Next i
    '
    Set execute = result
End Function
'

Insert a new VBA Class Module (name = Forward_NoIncome) and copy-paste the following code. This is a concrete implementation of IForward interface.

Option Explicit
Implements IForward
'
Private Function IForward_price(ByRef p As Scripting.Dictionary) As Double
    IForward_price = p.Item(Var.Spot) * Exp(p.Item(Var.Yield) * p.Item(Var.maturity))
End Function
'

Insert a new VBA Class Module (name = Forward_DiscreteIncome) and copy-paste the following code. This is another concrete implementation of IForward interface.

Option Explicit
Implements IForward
'
Private Function IForward_price(ByRef p As Scripting.Dictionary) As Double
    '
    IForward_price = (p.Item(Var.Spot) - p.Item(Var.CashflowPV)) * Exp(p.Item(Var.Yield) * p.Item(Var.maturity))
End Function
'

The previous program for pricing 20 forwards with two different pricing algorithms is implementing Strategy Design Pattern. The great thing in this pattern is, that now if you need to implement any new pricing algorithm, you can just "plug-in" a new interface implementation, without modifying any existing class. The only requirement is, that any new implementation must implement everything what the interface has. However, you are completely free to have any amount of private functions inside your implementations. In our forward pricing example, any implementation must implement this public function:

Option Explicit
'
' Interface to be implemented
Public Function price(ByRef p As Scripting.Dictionary) As Double
End Function
'

Constructor problem

In my last posting http://mikejuniperhill.blogspot.fi/2013/05/handling-parameters-dynamically-with.html I was opening up my current approach for having specific input parameters wrapped inside a data structure for allowing maximum flexibility, compared to the approach where you take all specific input parameters in a function interface separately. Now, If we think about that previous forward pricing example, how could we even use that latter approach? Interface public function (price), which we must implement for every implementation, is having a very specific signature for its input parameters. AFAIK, we cannot change that signature in our implementations.

This means, that if we have the following public interface:
Public Function price(ByVal a As Double) As Double

We cannot have the following implementations:
Private Function IForward_price(ByVal a As Double, ByVal c As Double) As Double
Private Function IForward_price(ByVal a As Integer) As Double
 
If we think this a bit more, why do we have such a problem with this issue after all? Answer: VBA does not have real constructors.

For example, in C# you also have interface implementation and any implementation must implement everything, what has been defined in interface. However, there you have constructors for all input parameters and those constructors does not need to have any homogenous signature for input parameters. I wrote the corresponding program in C# (a bit simpler main program) just for the comparison.

In this program, instead of feeding parameters inside interface price-method, we can use class constructors in a normal way for feeding required set of parameters to objects. In our VBA implementation, we are doing the same thing by wrapping required set of parameters into a data structure (parameter wrapper) and then feeding that data structure in interface price-method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace cApp_24052013
{
    class Program
    {
        static void Main(string[] args)
        {
            double f;
            IForward fwd = new Forward_NoIncome(100, 0.02, 1.25);
            ForwardPricer pricer = new ForwardPricer();
            f = pricer.execute(fwd);
            Console.WriteLine(f);
            //
            fwd = new Forward_DiscreteIncome(100, 7.25, 0.02, 1.25);
            f = pricer.execute(fwd);
            Console.WriteLine(f);
        }
    }
    public class ForwardPricer
    {
        public double execute(IForward f)
        {
            return f.price();
        }
    }
    public interface IForward
    {
        double price();
    }
    public class Forward_NoIncome : IForward
    {
        private double s;
        private double r;
        private double t;
        //
        public Forward_NoIncome(double s, double r, double t)
        {
            this.s = s;
            this.r = r;
            this.t = t;
        }
        public double price()
        {
            return s * Math.Exp(r * t);
        }
    }
    public class Forward_DiscreteIncome : IForward
    {
        private double s;
        private double d;
        private double r;
        private double t;
        //
        public Forward_DiscreteIncome(double s, double d, double r, double t)
        {
            this.s = s;
            this.d = d;
            this.r = r;
            this.t = t;
        }
        public double price()
        {
            return (s - d) * Math.Exp(r * t);
        }
    }
}
 
Well, that's all I wanted to share this time. Hopefully you have got some new ideas for your own programs. Have a great weekend!
-Mike

1 comment:

  1. Thank you for taking the time to write up this blog. I have been looking very hard to find decent design patterns for ms-access and this is the best insight I have found into using interfaces in VBA.

    ReplyDelete