Template Pattern

lua-users home
wiki

An implementation of Template Method Pattern (http://en.wikipedia.org/wiki/Template_method_pattern). Uses module as class. One file for each class. Based on Petite Abeille's module usage style. Using C++ example from http://login2win.blogspot.com/2008/06/c-template-pattern.html.

Abstract Base Class: Account

local require        = require
local setmetatable   = setmetatable
local getmetatable   = getmetatable
local error          = error
local assert         = assert
local print          = print

-- module declaration
module(...)
_VERSION = "1.0"

local class = setmetatable( _M, {} )
local meta  = getmetatable( class )

function meta:__tostring()
    return ( "%s/%s" ):format( self._NAME, self._VERSION )
end

function class:__tostring()
    return "Account"
end

-- Abstract Methods
function Start(self)
    error("abstract method: should be implemented by derived")
end

function Allow(self)
    error("abstract method: should be implemented by derived")
end

function End(self)
    error("abstract method: should be implemented by derived")
end

function MaxLimit(self)
    error("abstract method: should be implemented by derived")
end

-- Template Method
function Withdraw(self, amount)
    self:Start()
    
    local limit = self:MaxLimit()
    if amount < limit then
        self:Allow()
    else
        print("Not allowed")
    end
    
    self:End()
end

-- constructor
function meta:__call()
    error("private ctor!")
end

Derived Class: AccountNormal?

local require        = require
local getmetatable   = getmetatable
local setmetatable   = setmetatable
local error          = error
local assert         = assert
local print          = print
local tostring       = tostring

-- module declaration
module(...)
_VERSION = "1.0"

local Account  = require("account")
local class    = setmetatable( _M, {__index = Account} )
local meta     = getmetatable( class )

function meta:__tostring()
    return ( "%s/%s" ):format( self._NAME, self._VERSION )
end

function class:__tostring()
    return "AccountNormal"
end

local ometa = { __index = class, __tostring = function() return "AccountNormal" end }

local function InitInstance(self, name)
    self.name = name or "noname"
    --...
end

-- Implement Abstract Methods
function Start(self)
    print("[" .. self.name .. "] Start ...")
end

function Allow(self)
    print("[" .. self.name .. "] Allow ...")
end

function End(self)
    print("[" .. self.name .. "] End ...")
end

function MaxLimit(self)
    return 1000
end

-- constructor
function meta:__call( name )
    
    local c = setmetatable( {}, ometa )
    InitInstance(c, name)
    
    return c
end

Derived Class: AccountPower?

local require        = require
local getmetatable   = getmetatable
local setmetatable   = setmetatable
local error          = error
local assert         = assert
local print          = print
local tostring       = tostring

-- module declaration
module(...)
_VERSION = "1.0"

local Account  = require("account")
local class    = setmetatable( _M, {__index = Account} )
local meta     = getmetatable( class )

function meta:__tostring()
    return ( "%s/%s" ):format( self._NAME, self._VERSION )
end

function class:__tostring()
    return "AccountPower"
end

local ometa = { __index = class, __tostring = function() return "AccountPower" end }

local function InitInstance(self, name)
    self.name = name or "noname"
    --...
end

-- Implement Abstract Methods
function Start(self)
    print("[" .. self.name .. "] Start ...")
end

function Allow(self)
    print("[" .. self.name .. "] Allow ...")
end

function End(self)
    print("[" .. self.name .. "] End ...")
end

function MaxLimit(self)
    return 5000
end

-- constructor
function meta:__call( name )
    
    local c = setmetatable( {}, ometa )
    InitInstance(c, name)
    
    return c
end

Test:

local require = require
local print   = print

local Account       = require("account")
local AccountNormal = require("accountnormal")
local AccountPower  = require("accountpower")

-- local ab = Account() -- error! can't create instance of base class

local an0 = AccountNormal("an0")
an0:Withdraw(1500)

local an1 = AccountNormal("an1")
an1:Withdraw(1500)

local ap0 = AccountPower("ap0")
ap0:Withdraw(1500)

local ap1 = AccountPower("ap1")
ap1:Withdraw(1500)

Output:

>lua main.lua
[an0] Start ...
Not allowed
[an0] End ...
[an1] Start ...
Not allowed
[an1] End ...
[ap0] Start ...
[ap0] Allow ...
[ap0] End ...
[ap1] Start ...
[ap1] Allow ...
[ap1] End ...
>Exit code: 0

Download(5.1): Files:wiki_insecure/template-design-pattern.zip Download(5.2): Files:wiki_insecure/template-design-pattern-5.2.zip

-- HakkiDogusan


RecentChanges · preferences
edit · history
Last edited December 23, 2011 4:24 pm GMT (diff)