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.
Enrique Comba R. (Guest)
on 2007-05-10 10: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 R.
Pat M. (Guest)
on 2007-05-10 11:17
(Received via mailing list)
On 5/10/07, Enrique Comba R. <removed_email_address@domain.invalid> 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
Enrique Comba R. (Guest)
on 2007-05-10 11:25
(Received via mailing list)
Hey Pat!

On 10 May 2007, at 09:16, Pat M. 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
Pat M. (Guest)
on 2007-05-10 11:30
(Received via mailing list)
On 5/10/07, Enrique Comba R. <removed_email_address@domain.invalid> 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
Enrique Comba R. (Guest)
on 2007-05-10 12:05
(Received via mailing list)
On 10 May 2007, at 09:30, Pat M. 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
James G. (Guest)
on 2007-05-10 16:35
(Received via mailing list)
On May 10, 2007, at 1:56 AM, Enrique Comba R. 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 G. II
Enrique Comba R. (Guest)
on 2007-05-10 17:11
(Received via mailing list)
On 10 May 2007, at 14:33, James Edward G. II wrote:

> >>   def initialize(title, author)
> >> class ShortStory < Prose; end
> >>   end
>
> James Edward G. 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!
James G. (Guest)
on 2007-05-10 17:15
(Received via mailing list)
On May 10, 2007, at 8:10 AM, Enrique Comba R. 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 G. II
Enrique Comba R. (Guest)
on 2007-05-10 17:26
(Received via mailing list)
On 10 May 2007, at 15:14, James Edward G. II wrote:

>
> I feel it could be part of a discussion of the factory pattern.  It
> fits well there, I think.
>
> James Edward G. 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 R.
Anthony G. (Guest)
on 2007-05-10 18: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 R. <removed_email_address@domain.invalid> wrote:
On 10 May 2007, at 15:14, James Edward G. II wrote:

>
> I feel it could be part of a discussion of the factory pattern.  It
> fits well there, I think.
>
> James Edward G. 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 R.
Enrique Comba R. (Guest)
on 2007-05-10 18:12
(Received via mailing list)
On 10 May 2007, at 16:04, Anthony G. 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 R.
Anthony G. (Guest)
on 2007-05-10 18: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 R. <removed_email_address@domain.invalid> wrote:
On 10 May 2007, at 16:04, Anthony G. 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 R.
Robert K. (Guest)
on 2007-05-10 19:01
(Received via mailing list)
On 10.05.2007 15:25, Enrique Comba R. 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.
Enrique Comba R. (Guest)
on 2007-05-10 20:01
(Received via mailing list)
On 10 May 2007, at 17:00, Robert K. 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...
Chris G. (Guest)
on 2007-05-10 20: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!
Enrique Comba R. (Guest)
on 2007-05-10 20:15
(Received via mailing list)
On 10 May 2007, at 18:10, Chris G. 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 R.
This topic is locked and can not be replied to.