Thursday, October 9, 2008

Template Method

It has been said that in the software engineering field, the classic GOF book is a MUST READ bible. I never doubt this. However, i have always found it hard to digest. Not too long ago, i've found another book Design Patterns in Ruby, and i love it. It really makes all the concepts easier to grasp.

The first pattern it brought up is the 'template method', which is probably the easiest of all. Here's how it goes:
1.  class Report
2. def initialize(content)
3. @content = content
4. end
5. def output # template/skeletal method
6. output_header
7. output_body
8. output_footer
9. end
10. def output_body # abstract method
11. raise "Subclass MUST implement output_body"
12. end
13. def output_header ; end # hook (non-abstract) method
14. def output_footer ; end # hook (non-abstract) method
15. end
Notice the followings:
  • lines 5-9 ... defines the template (aka skeletal) method that delegates specific output actions individual methods
  • lines 10-12 ... defines the abstract method that MUST be implemented by subclasses, throwing of error is a workaround for the absence of abstract method in ruby (actually this is unnecessary, since ruby throws an undefined method error if it cannot find, anyway, its good to be informative)
  • lines 13 ... defines a hook method, which provides minimal default implementation and is meant to be overridden by subclasses (when appropriate)
Subclasses can be written and used as follows:
1.  class TextReport < Report
2. def output_body
3. puts @content.body
4. end
5. end
6.
7. class HtmlReport < Report
8. def output_header
9. puts "<html>"
10. end
11. def output_body
12. puts "<body>#{@content.body}</body>"
13. end
14. def output_footer
15. puts "</html>"
16. end
17. end
18.
19. [ TextReport, HtmlReport ].each do |report_class|
20. # outputs the appropriate report depending on report_class
21. report_class.new(content).output
22. end
SIMPLE !?

I've realized that without ever reading abt design patterns, i've already implemented this pattern in my php code, here's a fragment of my past php4 controller code:
1.  class AbstractWebController {
2. function process() { // template method
3. $action = $_POST['action']; // eg. destroy
4. $this->$action(); // variable method
5. }
6. }
7.
8. class MonsterController extends AbstractWebController {
9. function destroy() {
10. // monster destroying something ...
11. }
12. }
Well, it differs slightly from the original template method, as there is no distinct abstract or hook method. Instead, depending on value of $_POST['action'] (line 3), we call a variable method (line 4) in any subclass (line 10). By applying this pattern in any web framework, we can support arbitrary posted actions. NEAT rite ?!

No comments: