The Factory Method

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

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

···

On 5/10/07, Enrique Comba Riepenhausen <ecomba@mac.com> wrote:

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.

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

···

On May 10, 2007, at 1:56 AM, Enrique Comba Riepenhausen wrote:

Hey Pat!

···

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

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

Thanks a lot for the input!

Do you mind if I post your answer in Ruby Patterns? http://www.rubypatterns.org

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

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!

···

On 10 May 2007, at 14:33, James Edward Gray II wrote:

On May 10, 2007, at 1:56 AM, Enrique Comba Riepenhausen wrote:

Go for it.

Pst

···

On 5/10/07, Enrique Comba Riepenhausen <ecomba@mac.com> wrote:

Hey Pat!

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

>
> 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
>

Thanks a lot for the input!

Do you mind if I post your answer in Ruby Patterns? http://
www.rubypatterns.org

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

···

On May 10, 2007, at 8:10 AM, Enrique Comba Riepenhausen wrote:

Hey Pat!

>
> 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
>

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 :wink: http://www.rubypatterns.org/doku.php/gang_of_four_patterns:factory_method

···

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

On 5/10/07, Enrique Comba Riepenhausen <ecomba@mac.com> wrote:

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

Pst

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 :wink:

Cheers!

Enrique Comba Riepenhausen

···

On 10 May 2007, at 15:14, James Edward Gray II wrote:

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

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:

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

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 :wink:

Cheers!

Enrique Comba Riepenhausen

···

On 10 May 2007, at 15:14, James Edward Gray II wrote:

On May 10, 2007, at 8:10 AM, Enrique Comba Riepenhausen wrote:

---------------------------------
What kind of emailer are you? Find out today - get a free analysis of your email personality. Take the quiz at the Yahoo! Mail Championship.

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. :slight_smile:

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.

···

On 10.05.2007 15:25, Enrique Comba Riepenhausen wrote:

On 10 May 2007, at 15:14, James Edward Gray II wrote:

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

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 :wink:

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

···

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

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...

···

On 10 May 2007, at 17:00, Robert Klemme wrote:

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. :slight_smile:

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.

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

---------------------------------
Yahoo! Mail is the world's favourite email. Don't settle for less, sign up for your freeaccount today.

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!

···

--
Posted via http://www.ruby-forum.com/.

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

···

On 10 May 2007, at 18:10, Chris Gernon wrote:

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!

--
Posted via http://www.ruby-forum.com/\.