Re: Template Method Pattern (GoF) without abstract methods in Ruby
Austin Ziegler <[email protected]>
| Newsgroups | gmane.comp.lang.ruby.general |
|---|---|
| Message-ID | <CAJ4ekQt1Ts+VkvpVXm2YbGEh09FwVjvPp_v+hYFj6-prvWwD2Q@mail.gmail.com> |
GoF is not a recipe book. -a On Thu, Jan 10, 2019 at 11:59 AM Michael Schwarze <[email protected]> wrote: > Hi! > > I have some questions re. the Template Method Pattern (GoF) in Ruby. > > I need to update a simple management reporting system and have to add HTML > to the so far text-based reports. Looks to me like the classical use case > for the Template Method Pattern. I learned from Russ Olsen’s book »Design > Patterns in Ruby« that we do not have / use / „make up“ abstract methods in > Ruby. But a lot of infos concerning this topic on the web use these > 'abstract‘ methods by raising some kind of error upon calling the methods > (see [1, 2, 3]). > > Does anybody out there in real ruby code bases actually use this approach > with made up 'abstract‘ methods? > > I’ve come up with three simple and obviously contrived example > implementations without using abstract methods (and without meta > programming): > a) Inheritance from a simple(r) use case [4] > b) Inheritance from an 'abstract‘ class [5] > c) Composition by mixin of an 'abstract' module with the concerning > template method(s) [6] > > Anything I might have missed here? And which way is most idiomatic Ruby > (if at all;-) > > Many thanks! > > Cheers, > Michael > > > ~~~ > [1]: > https://medium.com/@dljerome/design-patterns-in-ruby-template-method-753443f5a1c8 > [2]: > https://github.com/pruett/ruby-patterns/blob/master/patterns/template_method.md > [3]: > https://stackoverflow.com/questions/12873873/ruby-base-class-call-child-class-like-in-abstract-classes/12873925#12873925 > > [4]: Example 1 - Inheritance from a simple(r) use case: > # Represents a simple (text) report > class Report > def initialize > @title = 'My Report' > @text = ['Line 1', 'Line 2.'] > end > > def output_report > output = head > output << body > output << footer > > output > end > > def head > "#{@title}\n" > end > > def body > output = '' > @text.each do |line| > output << "#{line}\n" > end > > output > end > > def footer > '' > end > end > > # Represents an HTML report, inherits from the simple text report > class HTMLReport < Report > def head > <<~HTML > <html> > <head> > <title>#{@title}</title> > </head> > HTML > end > > def body > output = "<body>\n" > @text.each do |line| > output << "<p>#{line}</p>\n" > end > output << "</body>\n" > > output > end > > def footer > "</html>\n" > end > end > > [5]: Example 2 - Inheritance from an 'abstract‘ class: > # Represents an abstract report / template method(s) > class Report > def initialize > @title = 'My Report' > @text = ['Line 1', 'Line 2.'] > end > > def output_report > output = head > output << body > output << footer > > output > end > end > > # Represents a text report > class TextReport < Report > def head > "#{@title}\n" > end > > def body > output = '' > @text.each do |line| > output << "#{line}\n" > end > > output > end > > def footer > '' > end > end > > # Represents an HTML report > class HTMLReport < Report > def head > <<~HTML > <html> > <head> > <title>#{@title}</title> > </head> > HTML > end > > def body > output = "<body>\n" > @text.each do |line| > output << "<p>#{line}</p>\n" > end > output << "</body>\n" > > output > end > > def footer > "</html>\n" > end > end > > [6]: Example 3 - Mixin of an 'abstract' module with the template method(s): > # Template method(s) for a report > module Report > def initialize > @title = 'My Report' > @text = ['Line 1', 'Line 2.'] > end > > def output_report > output = head > output << body > output << footer > > output > end > end > > # Represents a text report > class TextReport > include Report > > def head > "#{@title}\n" > end > > def body > output = '' > @text.each do |line| > output << "#{line}\n" > end > > output > end > > def footer > '' > end > end > > # Represents an HTML report > class HTMLReport > include Report > > def head > <<~HTML > <html> > <head> > <title>#{@title}</title> > </head> > HTML > end > > def body > output = "<body>\n" > @text.each do |line| > output << "<p>#{line}</p>\n" > end > output << "</body>\n" > > output > end > > def footer > "</html>\n" > end > end > > > Unsubscribe: <mailto:[email protected]?subject=unsubscribe> > <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk> > -- Austin Ziegler • [email protected] • [email protected] http://www.halostatue.ca/ • http://twitter.com/halostatue Unsubscribe: <mailto:[email protected]?subject=unsubscribe> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>