A new spin on the template method pattern using FP/OOP

In this section, we will demonstrate how the template method pattern can be implemented using imperative programming techniques, and we will refactor the code to write an FP one. As a concrete example, we plan to use the computation of Internal rate of return (IRR) as a running example.

To focus on the essentials, let us quickly hack an engine to compute the IRR, given a series of payments (List<double>), the rate, and the period. As a first step, we need to compute the present value of a series of payments by using the technique of discounting. The following routine computes the present value of the series of payments:

    public static double CashFlowPVDiscreteAnnual( 
    List<double> arr, double rate, double period) 
    { 
      int len = arr.Count; 
      double PV = 0.0; 
      for (int i = 0; i < len; ++i) 
      PV += arr[i] / Math.Pow((1+rate/100), i); 
      return PV; 
    } 

Note

The definition of IRR goes as follows:

An IRR is a computation that maps a series of payments that are supposed to accrue to the present value by finding the rate at which the series of payments has to be discounted to make the future value equivalent to the present value.

The following routine has been ported from the book, Financial Numerical Recipes in C++, Bernt Arne Odegard. For details, one can consult section 3.2.1 (material on IRR) of the book available on the Internet.

    public static double CashFlow_IRR_Annual(List<double> arr, 
    double rate,double period)  
    { 
      const double ACCURACY = 1.0e-5; 
      const int MAX_ITERATIONS = 50; 
      const double ERROR = -1e30; 
      double x1 = 0.0; 
      double x2 = 20.0; 
      // create an initial bracket,  
      // with a root somewhere between bot,top 
      double f1 = CashFlowPVDiscreteAnnual(arr,x1,period); 
      double f2 = CashFlowPVDiscreteAnnual(arr,x2,period); 
 
      for (int j = 0; j < MAX_ITERATIONS; ++j) 
      { 
        if ( (f1*f2) < 0.0)  {break; } 
 
        if (Math.Abs(f1) < Math.Abs(f2))  
          f1 = CashFlowPVDiscreteAnnual(arr, 
          x1+= 1.06*(x1-x2),period ); 
        else  
          f2 = CashFlowPVDiscreteAnnual(arr, 
          x2+=1.06*(x2-x1),period); 
        if (f2*f1>0.0) 
          return ERROR; 
      } 
      double f = CashFlowPVDiscreteAnnual(arr,x1,period); 
      double rtb; 
      double dx=0; 
      if (f<0.0) { 
        rtb = x1;dx=x2-x1; 
      } 
      else { 
        rtb = x2; dx = x1-x2; 
      } 
      for (int i=0;i<MAX_ITERATIONS;i++) 
      { 
        dx *= 0.5; 
        double x_mid = rtb+dx; 
        double f_mid = CashFlowPVDiscreteAnnual(arr,x_mid,period); 
        if (f_mid<=0.0) { rtb = x_mid; } 
        if ( (Math.Abs(f_mid)<ACCURACY) ||  
        (Math.Abs(dx)<ACCURACY) ) 
        return x_mid; 
      } 
      return ERROR; // error. 
    } 

With the routine under our belt, we can create an IRR calculation class that will use the template method pattern to receive the input for the computation of IRR, based on the series of future payments.

Let us create a class for the purpose of specifying inputs to the IRR computation sub system:

    public class IRR_PARAMS 
    { 
      public List<double> revenue { get; set; } 
      public double rate { get; set; } 
      public double period { get; set; } 
    } 

In the template method pattern implementation, we define an abstract base class, which does the bulk of the computation, and an abstract method, which the concrete class has to override to create an object out of it:

    public abstract class IRRComputationEngine 
    { 
      public abstract IRR_PARAMS Compute(); 
      public double Evaluate() 
      { 
        IRR_PARAMS par = Compute(); 
        if (par == null) return -1; 
        return CashFlow_IRR_Annual(par.revenue, 
        par.rate, par.period);  
      } 
      private static double CashFlow_IRR_Annual( 
      List<double> arr,double rate,double period) 
      { //----- Code Omitted } 
    } 
  } 

Since the compute method is flagged as abstract, we cannot instantiate an object. The main thing which we can do is override the class and provide the content of the abstract method.

    public class BridgeIRR :IRRComputationEngine { 
      IRR_PARAMS ps = new IRR_PARAMS(); 
      public BridgeIRR(List<double> rev, double period, double rate){ 
        ps.period = period; ps.rate = rate; ps.revenue = rev; 
      } 
      public override IRR_PARAMS Compute() { return ps;} 
    } 

We can use the preceding class as follows:

    double[] ns = { 10, 12, 13, 14, 20 }; 
    BridgeIRR test = new BridgeIRR(ns.ToList(),10,5); 
    double irr = test.Evaluate(); 
    Console.WriteLine(irr); 

Using FP for the template method pattern implementation

We will use lambda functions to simplify the template method pattern implementation. Instead of overriding a method after sub-classing the abstract class, we will use anonymous delegates to achieve the same objective. The resulting code, given next, is very simple and easy to understand:

    public class IRRComputationEngine2 
    { 
      public delegate IRR_PARAMS Compute(); 
      public Compute comp{get;set;}  
 
      public double Evaluate() 
      { 
        if (comp == null) return -1; 
        IRR_PARAMS par = comp(); 
        return CashFlow_IRR_Annual(par.revenue, 
        par.rate, par.period); 
      } 
      private static double CashFlow_IRR_Annual( 
        List<double> arr,double rate,double period) 
      { //--- Code Omitted } 
    } 

The class can be leveraged as follows:

    IRRComputationEngine2 n = new IRRComputationEngine2(); 
    double[] ns = { 10, 12, 13, 14, 20 }; 
    n.comp = () => { 
      IRR_PARAMS par = new IRR_PARAMS(); 
      par.revenue = ns.ToList(); 
      par.rate = 10; par.period = 5; 
      return par; 
    }; 
    double r = n.Evaluate(); 
    Console.WriteLine(r);

A quick note on the observer pattern

The functional programming model is well suited for implementing the observer pattern. Microsoft Corporation has already created a library, christened Rx, to exploit this synergy. This library implements a subset of features that falls under the category of compositional event streams. We will be covering the relationship between the observer pattern and functional programming from the next chapter onwards.

Does FP replace GoF patterns?

There is a notion among some programmers that functional programming can help to keep us away from GoF patterns. As far as the authors of this book are concerned, it is bit of an overstatement. In this chapter, we have already seen how GoF implementations can be made simple and better using functional language idioms. But the examples in this book are mostly written using C#. If we are using F# or Haskell, there are techniques available, in the rich type system of those languages, to do away with some of the GoF patterns.

Two examples are:

  • Partial function applications have made the builder pattern unnecessary for FP programming languages
  • Functional pattern matching helps us to eliminate the visitor pattern

If you take a closer look at the scheme of things, the GoF pattern was a solution for the static and rigid type system of C++. After that, languages such as Java node C#, on reflection, came to the fore to simplify the implementation of GoF patterns. The FP can be treated as yet another enhancement. A dynamic language with FP support can help us implement GoF patterns better, or sometimes completely do away with patterns. But, completely replacing GoF patterns is bit of a shot in the dark!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.63.136