The Strategy pattern is a delegation-based approach to solving the same problem as the Template Method pattern -- instead of breaking up the variable parts of your algorithm and implementating those parts in subclasses, you simply implement each version of your algorithm as a separate object. You can then vary the algorithm by supplying different strategy objects to the context.
The Strategy Pattern consists of strategies, which are interchangeable classes which encapsulate varieties of a particular algorithm, and the context class, which utilizes strategies. The context can choose different strategies depending on the situation.
Here are a couple code examples illustrating the Strategy Pattern:
# strategy class
class HtmlFormatter
def output_report(title, text)
puts "<h1>#{title}</h1>"
puts "<p>#{text}</p>"
end
end
# strategy class
class PlainTextFormatter
def output_report(title, text)
puts "***** #{title} *****"
puts text
end
end
# context class
class Report
attr_reader :title, :text
attr_accessor :formatter
def initialize(formatter)
@title = 'Monthly Report'
@text = 'Going great!'
@formatter = formatter
end
def output_report
@formatter.output_report(@title, @text)
end
end
report = Report.new(PlainTextFormatter.new)
report.output_report
report.formatter = HtmlFormatter.new
report.output_report
The Strategy Pattern can also be implemented using procs:
class Duck
attr_reader :name
attr_accessor :chirper
def initialize(&strategy)
@name = "Donald"
@chirper = strategy
end
def chirp
@chirper.call(self)
end
end
QUACK_CHIRPER = lambda do |context|
puts "Quack, my name is #{context.name}"
end
duck = Duck.new &QUACK_CHIRPER
duck.chirp