Skip to content

Commit

Permalink
My attempt at an algorithm using a Template Method.
Browse files Browse the repository at this point in the history
  • Loading branch information
aimee daniells committed Mar 30, 2010
1 parent 459b003 commit 5249c19
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.textile
Expand Up @@ -16,5 +16,6 @@ These are the patterns that i have implemented so far:
* "Decorator":http://github.com/sermoa/ruby_design_patterns/tree/master/structural_patterns/decorator/
* "Composite":http://github.com/sermoa/ruby_design_patterns/tree/master/structural_patterns/composite/
* "Iterator":http://github.com/sermoa/ruby_design_patterns/tree/master/behavioral_patterns/iterator/
* "Template Method":http://github.com/sermoa/ruby_design_patterns/tree/master/behavioral_patterns/template_method/

Please feel welcome to comment, add your feedback, suggest alternative implementations, point out my errors, and of course use for your own study and benefit. For a fast reference on how to implement design patterns in Ruby, i also recommend "shvets/design_patterns_in_ruby":http://github.com/shvets/design_patterns_in_ruby/.
11 changes: 11 additions & 0 deletions behavioral_patterns/template_method/README.textile
@@ -0,0 +1,11 @@
h2. Template Method

bq. Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redifine certain steps of an algorithm without changing the algorithm's structure.

I recently saw Jim Weirich show how the calculation of a square root could be refactored and generalised into an algorithm that can calculate any number by approximation and improving the estimate.

The algorithm is basically this: guess a number. Improve the guess until it's good enough, and then return the guess.

I thought this might be suitable for the template method. I have created an @ApproximationCalculator@ class which defines the general algorithm and provides a few methods that can be overridden when desired: @initial_guess@, @close_enough?@, @refine_guess@ and @final_answer@.

The @SquareRootCalculator@ overrides three of the methods in order to define particular parts of the equation.
@@ -0,0 +1,21 @@
class ApproximationCalculator

# template method
def self.do_calculation(number)
guess = initial_guess
while !close_enough?(guess, number)
guess = refine_guess(guess, number)
end
final_answer(guess)
end

# methods that can change
def self.initial_guess; 1; end

def self.close_enough?(guess, number); true; end

def self.refine_guess(guess, number); guess + 1; end

def self.final_answer(guess); guess; end

end
16 changes: 16 additions & 0 deletions behavioral_patterns/template_method/lib/square_root_calculator.rb
@@ -0,0 +1,16 @@
require 'approximation_calculator'
class SquareRootCalculator < ApproximationCalculator

def self.close_enough?(guess, number)
sprintf("%.5f", guess * guess) == sprintf("%.5f", number)
end

def self.refine_guess(guess, number)
guess - (((guess ** 2) - number) / (2 * guess)).to_f
end

def self.final_answer(guess)
((guess * (10 ** 5)).round) / (10 ** 5).to_f
end

end
24 changes: 24 additions & 0 deletions behavioral_patterns/template_method/test.rb
@@ -0,0 +1,24 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
Dir[File.dirname(__FILE__) + '/lib/*.rb'].each {|file| require file }

require 'test/unit'

class TestTemplateMethod < Test::Unit::TestCase

def test_square_root_of_9
assert_equal(3, SquareRootCalculator.do_calculation(9))
end

def test_square_root_of_100
assert_equal(10, SquareRootCalculator.do_calculation(100))
end

def test_square_root_of_1
assert_equal(1, SquareRootCalculator.do_calculation(1))
end

def test_square_root_of_2
assert_equal(1.41421, SquareRootCalculator.do_calculation(2))
end

end

0 comments on commit 5249c19

Please sign in to comment.