In this article, I would like to present you a design pattern that is not so common, but for sure, I wish, that in the past I would have used it. It would certainly make my life much easier. So, what is this Template method pattern all about?

The Template Method Pattern defines the skeleton of a an algorithm in one method. Some steps are deferred to subclasses, which are allowed to alter certain algorithm steps without changing the skeleton of an algorithm.

Say what?

Well, to simplify the definition, let’s look at an example. Imagine you have several product types. Your assigned task was to build a product catalogue on the web. All product types will use tables for representation, however not all products can be displayed the same. This is a perfect task for Template method pattern.

But why?

Think about it. Your catalogue needs to be displayed differently for each product, meaning you need to get different sets of product for each display. I agree, you could have written multiple agents, or just use multiple methods in an agent, but think about maintainability. And on top of it all, to display each product type, your algorithm is the same. First you need to do some initialization, then you need to select desired products. Next step is to process document set to create a display. In the end, all you need to do is print the results and terminate (or perform a clean up). Steps select and process are product type dependant. All other steps of the algorithm are common.

Example

For example let’s pretend that we have two types of products: regular classroom courses and e-courses. Regular classroom courses (or just courses) are scheduled courses, while e-courses are actually a 1 month subscription to some content (like video, PDF, etc.).

First, we need to create some storage classes: CProduct and CPrice, that will store information about products. This is more efficient than just have a collection of NotesDocuments.

Class CPrice
	Public strDesc As String
	Public dPrice As Double
End Class

Class CProduct
	m_strName As String
	m_strType As String
	Public m_Price() As CPrice

	Property Get Label As String
		Label = Me.m_strName
	End Property

	Property Get MyType As String
		MyType = Me.m_strType
	End Property

	Sub New (strName As String, strType As String)
		Me.m_strName = strName
		Me.m_strType = strType
		Redim Me.m_Price (0)
	End Sub

	Sub AddPrice (strDesc As String, dPrice As Double)
		Dim nIndex As Integer

		nIndex = 0
		If (Not Me.m_Price (0) Is Nothing) Then 
                     nIndex = Ubound (Me.m_Price) + 1
              End If

		Redim Preserve Me.m_price (nIndex)
		Set Me.m_price (nIndex) = New CPrice
		Me.m_Price (nIndex).strDesc = strDesc
		Me.m_Price (nIndex).dPrice = dPrice
	End Sub
End Class

Class CPrice contains a description of price (subscription or schedule date) and the price itself. Class CProduct defines a product. Each product can have multiple prices.

Now, to our abstract class that will define the algorithm and required methods.

Class CTemplateProduct
	m_strHtml As String
	m_products() As CProduct

	Sub Initialize()
		Redim m_products (0)
	End Sub

	Sub Select()
	End Sub

	Sub Process()
	End Sub

	Sub Print()
		Print m_strHtml
	End Sub

	Sub Terminate()
		Erase m_products
	End Sub

	Sub Run()
		Call Me.Initialize()
		Call Me.Select()
		Call Me.Process()
		Call Me.Print()
		Call Me.Terminate()
	End Sub
End Class

As you can see, methods Initialize, Print and Terminate are already implemented.
Next, we need to create classes for each product type. These classes will inherit from the abstract class.

Class CTemplateCourse As CTemplateProduct
   Sub Select()
      Redim Preserve Me.m_products (1)
      Set Me.m_products (0) = 
         New CProduct ("Course 1", "Lecture")

      Call Me.m_products (0).AddPrice ("Feb 3rd, 2009", 1000.0)

      Set Me.m_products (1) = 
         New CProduct ("Exam 1", "Lecture & exam")

      Call Me.m_products (1).AddPrice ("Feb 20th, 2009", 2000.0)
   End Sub

   Sub Process()
      Dim n As Integer
      Dim nPrice As Integer
      Dim nLBound As Integer
      Dim nUBound As Integer
      Me.m_strHtml = {<table border="0">}

      For n = Lbound (Me.m_products) To Ubound (Me.m_products)
         Me.m_strHtml = Me.m_strHtml & {<tbody><tr>}
         Me.m_strHtml = Me.m_strHtml & {<td colspan="2">}
         Me.m_strHtml = Me.m_strHtml & _
         Me.m_products (n).Label & { - }
        
         Me.m_strHtml = Me.m_strHtml & _
         Me.m_products (n).MyType & {</td>}
        
         Me.m_strHtml = Me.m_strHtml & {</tr>}
         Me.m_strHtml = Me.m_strHtml & {<tr>}

         nLBound = Lbound(Me.m_products (n).m_Price)
         nUBound = Ubound (Me.m_products (n).m_Price)
         For nPrice = nLBound To nUBound
            Me.m_strHtml = Me.m_strHtml & {<td>}
            Me.m_strHtml = Me.m_strHtml & _
            Me.m_products (n).m_Price (nPrice).strDesc 

            Me.m_strHtml = Me.m_strHtml & {</td>}
            Me.m_strHtml = Me.m_strHtml & {<td>}
            Me.m_strHtml = Me.m_strHtml & _
            Me.m_products (n).m_Price (nPrice).dPrice
            Me.m_strHtml = Me.m_strHtml & {</td>}
         Next
         Me.m_strHtml = Me.m_strHtml & {</tr>}
      Next

      Me.m_strHtml = Me.m_strHtml & {</tbody>}
   End Sub
End Class

Class CTemplateECourse As CTemplateProduct
   Sub Select()
      Redim Preserve Me.m_products (1)
      Set Me.m_products (0) = 
         New CProduct ("E-Course 1", "eBook")
      Call Me.m_products (0).AddPrice ("1 month", 100.0)

      Set Me.m_products (1) = 
         New CProduct ("E-Course 2", "ePresentation")

      Call Me.m_products (1).AddPrice ("1 month", 200.0)
   End Sub

   Sub Process()
      Dim n As Integer
      Dim nPrice As Integer
      Dim nLBound As Integer
      Dim nUBound As Integer

      Me.m_strHtml = {<table border="0">}

      For n = Lbound (Me.m_products) To Ubound (Me.m_products)
         Me.m_strHtml = Me.m_strHtml & {<tbody><tr>}
         Me.m_strHtml = Me.m_strHtml & {<td>} &_
         Me.m_products (n).Label & {</td>}
         Me.m_strHtml = Me.m_strHtml & {<td>} & _
         Me.m_products (n).MyType & {</td>}

         nLBound = Lbound(Me.m_products (n).m_Price)
         nUBound = Ubound (Me.m_products (n).m_Price)
         For nPrice = nLBound To nUBound
            Me.m_strHtml = Me.m_strHtml & {<td>} & _
            Me.m_products (n).m_Price (nPrice).strDesc

            Me.m_strHtml = Me.m_strHtml & {<br/>} & _
            Me.m_products (n).m_Price (nPrice).dPrice & {</td>}
         Next
         Me.m_strHtml = Me.m_strHtml & {</tr>}
      Next

      Me.m_strHtml = Me.m_strHtml & {</tbody></table>}
   End Sub
End Class

As you can no doubt see, I have simplified the Select method (this is due to me being to lazy to actually create a form, a view and some 6 documents). Also, method Process creates different HTML for each product type.

Interesting thing, this is about it.
All you have to do is some code that will use this. Here is my test agent, that should be run via browser.

Sub Initialize
	Dim course As CTemplateProduct
	Dim eCourse As CTemplateProduct

	Set course = New CTemplateCourse ()
	Call course.Run()

	Set eCourse = New CTemplateECourse()
	Call eCourse.Run()
End Sub