Forum: Ruby The Factory Method

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 08:57
(Received via mailing list)
Hi everyone,

as you know I started a few days ago the Ruby Patterns Wiki and now I
am starting to put in some samples. As you know, although I am not
new to software development, I am still a newbie in Ruby.

I was thinking about the Factory Method Pattern and following came to
my mind. If we follow the Pattern by the book (GoF) we would have
following code (simplified for the purpose of clarity):

class Product
   def hi
     "hello there"
   end
end

class ConcreteProduct < Product
   def hi
     "Hello from the concrete implementation"
   end
end

class Creator
   def create_product
   end
end

class ConcreteCreator < Creator
   def create_product
     ConcreteProduct.new
   end
end

Obviously this code strikes in Ruby (specially the creator class that
doesn't make much sense to me). How would you people think this could
be implemented in Ruby? Or better to say, what is the Ruby way to
solve this intent of the Factory Method Pattern: Define an interface
for creating an object, but let subclasses decide which class to
instantiate. Factory Method lets a class defer instantiation to
subclasses.

Cheers,

Enrique Comba Riepenhausen
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2007-05-10 09:17
(Received via mailing list)
On 5/10/07, Enrique Comba Riepenhausen <ecomba@mac.com> wrote:
> class Product
>
>
> Obviously this code strikes in Ruby (specially the creator class that
> doesn't make much sense to me). How would you people think this could
> be implemented in Ruby? Or better to say, what is the Ruby way to
> solve this intent of the Factory Method Pattern: Define an interface
> for creating an object, but let subclasses decide which class to
> instantiate. Factory Method lets a class defer instantiation to
> subclasses.

One clue is that the example is coded in Java, vs smalltalk.  The
reason for that is that Smalltalk doesn't really have the problem
they're solving here.  An "interface" is just going to be a bunch of
methods with the same method names and signatures.

I'm sure they discusss it in DP, but you don't need to implement this
pattern with an abstract class.  That's just there because you want
common behavior.  So how do you implement this pattern in Ruby?

class AmericanCoffeeShop
  def make_coffee
    Coffee.new :ingredients => [ :water, :mud ]
  end
end

class ItalianCoffeeShop
  def make_coffee
    Espresso.new
  end
end

Simple, you've implemented the factory method pattern.  We have an
interface - make_coffee - and each class can instantiate an object of
whatever kind it wants.

If some client code needs to have a coffee made, you can just pass it
an instance of either of those classes and it'll run fine.

Shared behavior can be provided by a mixin (whereas in Java you need a
superclass).

module CoffeeProvider
  def order
    take_payment
    give_change
    make_coffee
  end
end

class AmericanCoffeeShop
  include CoffeeProvider

  def make_coffee
    Coffee.new :ingredients => [ :water, :mud ]
  end
end

class ItalianCoffeeShop
  include CoffeeProvider

  def make_coffee
    Espresso.new
  end
end

Now we've achieved the desired behavior.  We've defined the high-level
behavior of taking an order, but placed the responsibility on
lower-level implementation details in another class.  Now anyone can
come along and write a class that knows how to provide an order of
coffee, all without any foresight from the initial author of
CoffeeProvider.

Pat
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 09:25
(Received via mailing list)
Hey Pat!

On 10 May 2007, at 09:16, Pat Maddox wrote:

> class AmericanCoffeeShop
>
> module CoffeeProvider
>  def make_coffee
> end
>
> Now we've achieved the desired behavior.  We've defined the high-level
> behavior of taking an order, but placed the responsibility on
> lower-level implementation details in another class.  Now anyone can
> come along and write a class that knows how to provide an order of
> coffee, all without any foresight from the initial author of
> CoffeeProvider.
>
> Pat
>

Thanks a lot for the input!

Do you mind if I post your answer in Ruby Patterns? http://
www.rubypatterns.org
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2007-05-10 09:30
(Received via mailing list)
On 5/10/07, Enrique Comba Riepenhausen <ecomba@mac.com> wrote:
> > I'm sure they discusss it in DP, but you don't need to implement this
> >  def make_coffee
> >
> >
> >
> > CoffeeProvider.
>
Go for it.

Pst
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 10:05
(Received via mailing list)
On 10 May 2007, at 09:30, Pat Maddox wrote:

>> > methods with the same method names and signatures.
>> > end
>> > whatever kind it wants.
>> >  def order
>> >    Coffee.new :ingredients => [ :water, :mud ]
>> >
>> >
>>
>> Thanks a lot for the input!
>>
>> Do you mind if I post your answer in Ruby Patterns? http://
>> www.rubypatterns.org
>>
>>
>>
>
> Go for it.

Done ;) http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-10 14:35
(Received via mailing list)
On May 10, 2007, at 1:56 AM, Enrique Comba Riepenhausen wrote:

> I was thinking about the Factory Method Pattern and following came
> to my mind.

In addition to Pat's great answer, I think it's important to note
that classes are objects in Ruby.  This often aids in Factory pattern
scenarios.  For example:

 >> class Prose
 >>   def initialize(title, author)
 >>     @title = title
 >>     @author = author
 >>   end
 >>   def inspect
 >>     "#{self.class}:  #{@title} by #{@author}"
 >>   end
 >> end
=> nil
 >> class Novel < Prose; end
=> nil
 >> class ShortStory < Prose; end
=> nil
 >> class Author
 >>   def initialize(name)
 >>     @name = name
 >>   end
 >>   def to_s
 >>     @name
 >>   end
 >>   def write(type, title)
 >>     type.new(title, self)
 >>   end
 >> end
=> nil
 >> james = Author.new("James")
=> #<Author:0x14a11d0 @name="James">
 >> james.write(Novel, "Ruby:  The Girl I Loved")
=> Novel:  Ruby:  The Girl I Loved by James
 >> james.write(ShortStory, "Little Ruby Riding Hood")
=> ShortStory:  Little Ruby Riding Hood by James

Just some more food for thought.

James Edward Gray II
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 15:11
(Received via mailing list)
On 10 May 2007, at 14:33, James Edward Gray II wrote:

> >>   def initialize(title, author)
> >> class ShortStory < Prose; end
> >>   end
>
> James Edward Gray II

Thanks a lot James, I think this clarifies (at least from the newbie
point of view) a lot of the power under the hood in Ruby!

I'm now thinking where to include this in the Wiki.

  Any idea?

Cheers, and thanks again!
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-05-10 15:15
(Received via mailing list)
On May 10, 2007, at 8:10 AM, Enrique Comba Riepenhausen wrote:

> Thanks a lot James, I think this clarifies (at least from the
> newbie point of view) a lot of the power under the hood in Ruby!

Sure.

> I'm now thinking where to include this in the Wiki.
>
>  Any idea?

I feel it could be part of a discussion of the factory pattern.  It
fits well there, I think.

James Edward Gray II
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 15:26
(Received via mailing list)
On 10 May 2007, at 15:14, James Edward Gray II wrote:

>
> I feel it could be part of a discussion of the factory pattern.  It
> fits well there, I think.
>
> James Edward Gray II
>

Yep! Included! http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method

By the way, feel free to edit the wiki in your liking. I actually set
it up as a collaborative project where we all can share our knowledge
in the Design Pattern implementation and discoveries in Ruby ;)

Cheers!

Enrique Comba Riepenhausen
7529d5f2a3abf50f74573a5e99a1b18b?d=identicon&s=25 Anthony Gardner (Guest)
on 2007-05-10 16:05
(Received via mailing list)
Enrique,

This is a good idea. As I'm currenlty looking at patterns with regards
to Perl and Ruby .... this will whet my appetite more.

-Ants

Enrique Comba Riepenhausen <ecomba@mac.com> wrote:
On 10 May 2007, at 15:14, James Edward Gray II wrote:

>
> I feel it could be part of a discussion of the factory pattern.  It
> fits well there, I think.
>
> James Edward Gray II
>

Yep! Included! http://www.rubypatterns.org/doku.php/
gang_of_four_patterns:factory_method

By the way, feel free to edit the wiki in your liking. I actually set
it up as a collaborative project where we all can share our knowledge
in the Design Pattern implementation and discoveries in Ruby ;)

Cheers!

Enrique Comba Riepenhausen
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 16:12
(Received via mailing list)
On 10 May 2007, at 16:04, Anthony Gardner wrote:

> Enrique,
>
> This is a good idea. As I'm currenlty looking at patterns with
> regards to Perl and Ruby .... this will whet my appetite more.
>
> -Ants

You are free to add your findings in the Wiki Ants! I will take care
of the formating if there is need... I appreciate any input!

Cheers,

Enrique Comba Riepenhausen
7529d5f2a3abf50f74573a5e99a1b18b?d=identicon&s=25 Anthony Gardner (Guest)
on 2007-05-10 16:30
(Received via mailing list)
errrm, just had a look at the cofee factory, and haven;t you actually
missed off the factory part?

Enrique Comba Riepenhausen <ecomba@mac.com> wrote:
On 10 May 2007, at 16:04, Anthony Gardner wrote:

> Enrique,
>
> This is a good idea. As I'm currenlty looking at patterns with
> regards to Perl and Ruby .... this will whet my appetite more.
>
> -Ants

You are free to add your findings in the Wiki Ants! I will take care
of the formating if there is need... I appreciate any input!

Cheers,

Enrique Comba Riepenhausen
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-05-10 17:01
(Received via mailing list)
On 10.05.2007 15:25, Enrique Comba Riepenhausen wrote:
>>> I'm now thinking where to include this in the Wiki.
> http://www.rubypatterns.org/doku.php/gang_of_four_...
>
> By the way, feel free to edit the wiki in your liking. I actually set it
> up as a collaborative project where we all can share our knowledge in
> the Design Pattern implementation and discoveries in Ruby ;)

I'd go even further and point out that *every* class[1] in Ruby is a
concrete factory - maybe even at the start of the article.  In the most
general way the interface is new() i.e. what you would call a "default
constructor" in other languages.  Few know that classes usually also
provide method #allocate to create an instance of the class but without
invoking #initialize.  So that would be the second factory method that
all classes support. :-)

Also, you can create any number of additional factory methods on a
class, if you wish so.

And finally, since there are no interfaces in Ruby the pattern might be
less obvious, even if implemented "properly", i.e. with concrete
creation methods. (I think you do mention that on the Wiki already.)

Kind regards

  robert


[1] excluding classes that do not support #new.
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 18:01
(Received via mailing list)
On 10 May 2007, at 17:00, Robert Klemme wrote:

>
> [1] excluding classes that do not support #new.
Thanks for the clarification Robert! I included it actually in the
Wiki as I think it'll help to further understand this concepts in
Ruby...
De271a04fe7a67b884ce75404c1dcc61?d=identicon&s=25 Chris Gernon (kabigon)
on 2007-05-10 18:10
Thank you so much for this discussion, and for starting the wiki.

I picked up "Head First Design Patterns" a while back to try to learn
design patterns. The book is completely Java-oriented, but I thought I
could use my knowledge of Ruby to "translate" the lessons in the book (I
don't have any Java experience). By an unfortunate coincidence, though,
the first pattern they covered was the Factory pattern, and based on my
Ruby experience, not only couldn't I figure out how to do it in Ruby, I
couldn't even understand what problem they were trying to solve! I put
it down for a while and moved on to other computer books. Now that this
wiki is up and running, though, I do believe I'll go back and tackle it
again!
Dcef09335767135acb26ecfebbc65198?d=identicon&s=25 Enrique Comba Riepenhausen (Guest)
on 2007-05-10 18:15
(Received via mailing list)
On 10 May 2007, at 18:10, Chris Gernon wrote:

> Ruby experience, not only couldn't I figure out how to do it in
>
Hey Chris!

Thanks a lot! You are welcome to post your findings in the Wiki and
help to improve the body of knowledge even more there. I think it is
a great thing to do and I am happy that it might help some of us...

Cheers,

Enrique Comba Riepenhausen
This topic is locked and can not be replied to.