Re: Template Method Pattern (GoF) without abstract methods in Ruby

Austin Ziegler <[email protected]>
Newsgroups gmane.comp.lang.ruby.general
Message-ID <CAJ4ekQsUSNB_9xY4mvypYzB0KoS2Juiw_u8Y-30cJ7cYw5887Q@mail.gmail.com>
If you’re making a report generator, you would want to use either
inheritance or decoration.

class ReportGenerator
  def initialize(thing_to_report_on)
    @thing_to_report_on = thing_to_report_on
  end

  def generate
    parse
    format
    output
  end
end

You might implement `parse` and `output` the same in the `ReportGenerator`,
but `format` would be different per sub-class.

The ultimate decoration, however, would be to have your generator, and then
do:

generator = ReportGenerator.new(data_for_report)
generator.extend(HTMLReportFormatter)
generator.generate

That’s a per-object mixin.

You can also do this with separate pieces:

class ReportGenerator
  def prepare
  end
end

class HTMLReportFormatter; def format(prepared_report); ...; end; end
class TextReportFormatter; def format(prepared_report); ...; end; end

rg = ReportGenerator.new(item).prepare
HTMLReportFormatter.new(rg)

What makes the most sense is what reads best to you and what will be
easiest to maintain.

For me, that depends on the rest of the code and what I’m trying to solve.
I have pretty much solved all of these in different ways every time, but
with Ruby I tend to shift toward duck-typing as much as possible.

-a

On Fri, Jan 11, 2019 at 5:20 PM Michael Schwarze <[email protected]>
wrote:

> Hi Austin,
>
> > Am 11.01.2019 um 17:52 schrieb Austin Ziegler <[email protected]>:
>
> Many thanks for your patience and your explanations!
>
> > But that’s my point. If you’re trying to implement the `Template Method
> Pattern`, you’re trying to use GoF as a recipe book. This is a mistake and
> will only hinder your learning of Ruby.
>
> Sorry, my English is probably worse than my Ruby ;-) I’m not really
> focussed on implementing the pattern 'by the book‘ but I think my problem
> is in the realm of the Template Method Pattern...
>
> > What problem are you actually trying to solve?
>
> A simple management report which was text-only so far and should get an
> additional HTML output now; both following the same process / outline in
> generating the slightly differing output. That’s why I supplied the three
> made-up code examples with my initial email.
>
> > In Ruby, you quite *literally* don’t need abstract methods.
>
> That was my understanding from the book, too. I did a web research but the
> results confused me, as they contained mainly abstract methods in Ruby.
> Hence my request to this list.
>
> > class Processor
> >   def process
> >     step1
> >     step2
> >     step3
> >     finalize
> >   end
> >
> >   private
> >
> >   def finalize
> >     # finalize the process here
> >   end
> > end
> >
> > class Foo < Processor
> >   private
> >
> >   def step1; end
> >   def step2; end
> >   def step3; end
> > end
>
> Code helps - that’s the discussion I was looking for! That’s close to my
> example 2...
>
> > If I do Processor.new.process, I will get a NoMethodError because I have
> no implementation of `step1`, `step2`, or `step3`. If I do
> `Foo.new.process`, it works. You don’t need abstract methods in Ruby
> because the methods don’t have to exist during compilation, because there’s
> no compilation phase or static method resolution.
>
> Ok, I get this. So you are suggesting inheritance here, but why use a
> class you will probably never instantiate? Why not mixin a module with the
> common methods (my example 3)?
>
>   module Processor
>     def process
>       step1
>       step2
>       step3
>       finalize
>     end
>
>     def finalize; end
>   end
>
>   class Foo
>     include Processor
>
>     def step1; end
>     def step2; end
>     def step3; end
>   end
>
>   class Bar
>     include Processor
>
>     def step1; end
>     def step2; end
>     def step3; end
>   end
>
> Or, when preferring inheritance, why not inheriting from the simple use
> case (my example 1):
>
>   class Foo # simple text
>     def process
>       step1
>       step2
>       step3
>       finalize
>     end
>
>     def step1; end
>     def step2; end
>     def step3; end
>     def finalize; end
>   end
>
>   class Bar # complex HTML
>     def process
>       step1
>       step2
>       step3
>       finalize
>     end
>
>     def step1; end
>     def step2; end
>     def step3; end
>     def finalize; end
>   end
>
> All three approaches do work but which one would do Ruby experts prefer
> for solving this problem?
>
> Cheers,
> Michael
>
> 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>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.